Java第三次作业
学习总结
1.阅读下面程序,分析是否能编译通过?如果不能,说明原因。应该如何修改?程序的运行结果是什么?为什么子类的构造方法在运行之前,必须调用父 类的构造方法?能不能反过来?
class Grandparent {
public Grandparent() {
System.out.println("GrandParent Created.");
}
public Grandparent(String string) {
System.out.println("GrandParent Created.String:" + string);
}
}
class Parent extends Grandparent {
public Parent() {
System.out.println("Parent Created");
super("Hello.Grandparent.");
}
}
class Child extends Parent {
public Child() {
System.out.println("Child Created");
}
}
public class Test{
public static void main(String args[]) {
Child c = new Child();
}
}
不能通过编译
-
原因:当调用Parent类中的构造方法时,Parent类的会自动调用其父类的构造方法,Parent类的构造方法调用的是父类的含参构造方法,因此
要显示使用super语句,但是super语句必须是第一个可执行的语句,但是在此构造方法中super不是第一个可执行语句,因此不能通过编译 -
修改:将super语句删除,直接调用父类的无参构造方法,或者将super语句移动到第一句
2.阅读下面程序,分析程序中存在哪些错误,说明原因,应如何改正?正确程序的运行结果是什么?
class Animal{
void shout(){
System.out.println("动物叫!");
}
}
class Dog extends Animal{
public void shout(){
System.out.println("汪汪......!");
}
public void sleep() {
System.out.println("狗狗睡觉......");
}
}
public class Test{
public static void main(String args[]) {
Animal animal = new Dog();
animal.shout();
animal.sleep();
Dog dog = animal;
dog.sleep();
Animal animal2 = new Animal();
dog = (Dog)animal2;
dog.shout();
}
}
- 错误有两个
- 1.animal。sleep();上转型不能调用子类增加的方法
- 2.dog.shout();下转型中如果父类对象是有父类直接定义的,那么在下转型时编译不会出错,但是运行时会报错,原因是不能判断父类的
对象是否是子类的实例,应下转型之前用instanceof判断父类对象是否是子类的实例
//修改
if(animal2 instanceof Dog){//如果animal2是dog类的的对象,那么继续执行下转型
dog=(Dog)animal2;
}
3.运行下列程序
class Person {
private String name ;
private int age ;
public Person(String name,int age){
this.name = name ;
this.age = age ;
}
}
public class Test{
public static void main(String args[]){
Person per = new Person("张三",20) ;
System.out.println(per);
System.out.println(per.toString()) ;
}
}
- 1.程序的运行结果如下,说明什么问题?
Person@166afb3
Person@166afb3
-
说明如果不进行toString方法重写的话,输出对象和输出对象的toString方法的结果是相同的
-
2.那么,程序的运行结果到底是什么呢?利用eclipse打开println(per)方法的源码,查看该方法中又调用了哪些方法,能否解释本例的运行结果?
-
3.在Person类中增加如下方法,
public String toString(){
return "姓名:" + this.name + ",年龄:" + this.age ;
}
重新运行程序,程序的执行结果是什么?说明什么问题?**
//结果
姓名:张三,年龄:20
姓名:张三,年龄:20
- 说明pbject类中的toString方法输出的是对象的引用,只有通过重写toString方法才可以输出具体的内容
4.汽车租赁公司,出租汽车种类有客车、货车和皮卡三种,每辆汽车除了具有编号、名称、租金三个基本属性之外,客车有载客量,货车有载货量,皮卡则同时具有载客量和载货量。用面向对象编程思想分析上述问题,将其表示成合适的类、抽象类或接口,说明设计思路。现在要创建一个可租车列表,应当如何创建?
- 定义抽象类具有抽象方法getNumber,getname,getMoney方法
- 定义接口a具有输出载货量的抽象方法,定义接口b具有输出载客量的方法
- 定义三个子类客车,三个属性,set,get,toString方法,货车,皮卡继承抽象类,客车实现接口b,货车实现接口a,皮卡实现接口a,b
- 在测试类中实例化客车类,货车类,皮卡类,调用子类中的重写的toString方法输出相关信息
5.阅读下面程序,分析代码是否能编译通过,如果不能,说明原因,并进行改正。如果能,列出运行结果
interface Animal{
void breathe();
void run();
void eat();
}
class Dog implements Animal{
public void breathe(){
System.out.println("I'm breathing");
}
void eat(){
System.out.println("I'm eating");
}
}
public class Test{
public static void main(String[] args){
Dog dog = new Dog();
dog.breathe();
dog.eat();
}
}
不能
- 定义了一个借口 Dog类实现了这个接口,那Dog类应把接口中的所有的抽象方法都进行定义
//修改 在Dog类中加入如下方法
public void run(){
System.out.println("I'm runing");
}
6 其他总结
接口
实现类的多继承
- 接口中只能含有公有的静态常量和抽象方法
- 公有的public 静态static 常量final public static final int A=100;
- 抽象方法 publuc abstract void a():
接口与抽象类的区别
- 接口中只有公有静态常量和抽象方法,而抽象类中除了常量和抽象方法,还可以有变量和普通方法
- 接口中不能有静态代码块和静态方法
- 一个类只能继承一个抽象类,但是却能实现多个接口
- 接口是侧重于事物能做什么,将多个事物具有的共同行为抽象出来在接口中以抽象方法的形式保存起来,而抽象类侧重于事物的特点,将多个事物具有的相同的属性和行为抽象出来在抽象类中保存起来。即多个事物如果具有相同的行为,那么就用接口保存起来,如果多个事物具有相同的属性和部分相同的行为,那么就用抽象类来保存。
- 因为抽象类是多个事物相同属性和行为的集合,所以抽象类是一种模板式设计,所有的子类在此基础上对其进行修改即可,如果他们的公共部分需要修改那么只需修改抽象类即可
- 接口是一种辐射式设计,如果接口中的成员进行了变化,那么所有实现接口的类都需要进行改变
接口的定义
[public]/*不加public此接口只能被一个包中的类访问*/ interface 接口名[extends 父接口列表/*多个接口时用逗号隔开]*/
public static final int A=100; //public sattic final可以在接口中可以省略 编译时自动添加
public abstract void a(); // public abstract 在接口中可以省略 编译时自动添加
接口的实现
用implements子句来表示一个类使用了某个接口
- 一个类可以使用多个接口,只需在接口名后加逗号
- 类中必须定义接口的所有抽象方法
class Stu implements 接口列表{
。。。。。
定义抽象方法//定义抽象方法必须显示的声明public 不然会被认为是缩小了权限
}
接口回调
把一个实现接口的类所创建的对象的引用赋给接口所声明的变量,那么这个接口就可以调用类中定义的方法
- 接口回调实现多态
interfaceSpeakHello{
void speakHello();
}
class Chinese implements SpeakHello{
public void speakHello(){
System.out.println("你吃饭了吗");
}
}
class English implements SpeakHello{
public void speakHello(){
System.out.println("今天天气不错");
}
}
class KindHello{
public void lookHello(SpeakHello speakhello){//参数定义为一个接口变量,接收类对象的引用
speakhello.speakHello();//接口回调
}
}
//测试类
public class Test{
public static void main(String[] args){
KindHello kindhello=new KindHello();
kindhello.lookHello(new Chinses());//输出吃饭了吗
kindhello.lookHello(new English());//输出今天天气不错
//一个方法输出不同情况 多态性实现
}
}
工厂模式设计
将创建对象的过程屏蔽起来,使之可以动态的实例化对象
interface Fruit{
public abstract void eat();
}
class Apple implements Fruit{
public void eat(){
//输出 吃苹果
}
}
class Orange implements Fruit{
public void eat(){
//输出 吃橘子
}
}
//测试类 非工厂模式
public class Test{
public static void main(String[] args){
System.out.println("想吃什么水果");
//输入想吃的水果
//实例化对应的对象 //工厂模式即屏蔽实例化的过程,输入想吃的水果后立即调用相应的eat方法
//调用对象的eat方法
}
}
//工厂模式
//添加一个类用来动态实例化对象
class Factory{
public static Fruit getInstance(String name){ //返回类型为接口类型
Fruit f=null;//声明一个接口变量,用来接收类的对象,进行接口回调
if("apple".equals(name)){
f=new Apple();
}
else if("Orange".equals(name)){
f=new Orange();
}
retuen f;//返回相应的对象的引用
}
}
//测试类
public class Test{
public static void main(String[] args){
System.out.println("想吃什么水果");
//输入想吃的水果
Fruit f=Factory.getInstance("水果名");//输入水果的过程就进行了实例化
if(f!=null){
//调用对象的eat方法
}
}
}
子类
子类的声明:
类体
}```
```java
//定义一个父类
class Person{
private String name;
private int age;
piblic void setName(String name){}
public String getName(){}
//age的set、get方法
}
//定义一个子类
class Student extends Person{
private String school;
//school的set、get方法
}
//定义测试类
public class Test{
public static void main(String[] arsg){
Student stu=new Student();//调用子类的构造方法,运行前会执行父类的无参构造方法
stu.setName();//继承了父类的方法,**调用子类中的setName()方法**输入姓名属性
stu.setage();;//继承了父类的方法,调用setAge输入年龄属性
stu.setSchool();//调用子类的setSchool()方法。输入学校
}
}
因为是继承父类,所以父类的方法也属于子类,stu.setName(),这个方法调用的也是子类中的方法
- Java中所有类如果没有写extends,那么这个类是继承的java.lang.Object这个类
- 类继承具有传递性,因此所有的类都直接或间接的继承java.lang.Obiect类
- 子类不能访问权限为private的变量和方法
子类构造方法的继承原则
- 子类会无条件的继承父类的构造方法,在执行子类的构造方法时首先执行父类的构造方法
- 如果子类没有构造方法,那子类会继承父类的无参构造方法
- 可以在子类的构造方法中用super关键字来调用父类的含参构造方法,super语句需要是第一个执行的语句
- 当子类中没有显示的调用父类构造方法(没有写super关键字),而父类中又没有无参构造方法,此时会编译出错
子类继承方法的重写
子类对父类的方法进行重新定义的过程叫做方法的重写
- 重写的方法要和被重写的方法具有相同方法名、参数列表、返回值类型——即除了方法体不同其余全部相同
- 重写后的方法的访问权限不能比被重写方法的访问权限还要小
super关键字
- 在子类中调用父类中的方法需要用super关键字声明
super.方法
- 子类调用父类的构造方法只需在关键后的括号内输入实参即可
super("hello");
final关键字
final意为最后的,即是不可改变的
- final定义的类不能有被继承的类,即不能有子类
- final定义的方法不能被改变,即不能被重写
- final定义的变量不可以改变,即变量为一个常量
- 声明全局常量:final static int a=100;
多态性
多态是指相同的方法名但是作用不同
- 实现多态性有两种方法:
1.覆盖实现多态:子类重写的方法覆盖父类方法
- 重载实现多态:根据参数调用不同方法
- 覆盖实现多态的特点:
1.覆盖实现多态实质上是方法的重写,因此除方法体不同其余皆相同
2.覆盖实现多态是子类重写父类方法,因此方法的权限必是可继承的,所以重写后的方法权限不可小于父类权限
3.覆盖方法实现多态重写时不能将方法私有化
class Animal{
public void cry(){
System.out.println("我是动物,我不知道怎么叫");
}
}
class Cat extends Animal{
public void cry(){
System.out.println("喵喵叫");//在Cat类中重写cry实现多态
}
}
class Dog extends Animal(){
public void cry(){
System.out.println("汪汪叫");//在Dog类中重写cry方法实现多态
}
}
//测试类
public class Test{
public static void main(String arsg[]){
Cat cat=new Cat();
cat.cry();//调用重写后的cry方法
}
}
对象转型
上转型对象
上转型对象:使父类对象引用指向一个子类实例
- 上转型格式:父类名 父类对象=new 子类名(子类实例);
- 上转型的叫法:父类对象xxx是子类对象的上转型对象
上转型对象的特点:
- 上专性对象不能对子类新添加的变量或方法进行操作
- 上转型对象调用的方法只能是子类重写过的方法以及继承且没有修改的方法
- 上转型对象可以调用子类继承或隐藏的变量
class Person{
public void eat(){
System.out.println("我什么都喜欢吃");
}
}
class Student extends Person{
public void eat(){
System.out.println("我喜欢吃冰激凌");
}
}
//定义测试类
public class Test{
public static void main(String[] arsg){
Person p=new Student();//父类对象p是子类Student的上转型对象
p.eat();//输出的是喜欢吃冰激凌,重写父类eat方法
}
}
下转型对象
下转型对象是将父类实例的引用赋给一个子类的对象
- 下转型的格式:子类名 对象名=(子类)父类实例;
- 下转型对象需要强制转换
- 叫法:子类xxx是父类的一个下转型对象
下转型的两种情况
- 需要转型的对象是由子类向上转型而来的,此时不会出错
Person p=new Student();
Student s=(Student)p;//对象p是由子类Student上转型而来,p的引用指向的子类的对象
2.需要转型的对象是父类的对象
Person p=new Person();
Student s=(Student)p;//p的引用是父类的对象,此时不能判断Student类是Person类的子类,所以会出错
解决需要转型的对象的引用是父类对象引用的方法
//instanceof关键字
Person p=new Person();
Student s=new Student();
if(p instanceof Student){//如果转型对象p是Student类的实例,执行s=p
s=p;//向下转型//如果p不是Student类的实例,下转型失败
}
向上转型的作用
class Animal{
public void cray(){
Ssytem.out.println("我是动物,我不知道怎么叫");
}
}
class Cat extends Animal{
public void cray(){
Ssytem.out.println("喵喵叫");
}
}
class Dog{
public void cray(){
Ssytem.out.println("汪汪叫");
}
}
//测试类
public class Test{
public static void main(String[] arsg){
animalCry(new Cat);/*调用animalCry方法传入一个子类实例,通过上转型然后调用上转型对象中的cry方法,但是因为是上转型,所以调用的是子类重写过的cry方法,通过这种方法使之在想输出多个子类对象的cry方法时只需定义一个animalCry方法*/
animalCry(new Dog);
}
public static void animalCry(Animal animal){//animal=new Cat;向上转型,方法体中调用的是重写过的方法
animal.cry();
}
}
抽象类
用abstract修饰的类叫做抽象类
用abstract修饰的方法叫做抽象方法
抽象类的特点:
- 抽象类不能有final关键字,因为使用抽象类来达到目的必须要有派生子类,因此不能加final关键字
- 抽象类中可以有抽象方法和普通方法,也可以没有
- 抽象类不能使用new关键字创建对象,只能产生子类,创建子类的对象
- 抽象类的子类必须实现父类的所有抽象方法,抽象类可以看作是多个类所具有的共同的特点的集合,如同学生,老师,大人小孩都是人的集合中的一部分一样,抽象类中的属性是多个类中都具有的属性,因此在使用子类时肯定要使用到抽象类中的所有抽象方法,因此肯定会定义每一个抽象方法
抽象类声明的对象可以成为子类的上转型对象,调用子类重写的方法。
abstract class Animal{
public abstract void cry();
}
class Cat extends Animal{
public void cry(){ System.out.println("猫猫叫!"); }
}
class Dog extends Animal{
public void cry(){ System.out.println("汪汪叫!"); }
}
//测试类
public class Test{
public static vodi main(Stting arsg[]){
Animal animal=new Cat();//cat对象上转型
animal.cry();//输出cat类重写的方法
}
}
面向抽象编程
在设计程序时先声明抽象类,类中声明抽象方法,抽象方法的具体内容由非抽象子类完成,在编程上将抽象类声明的对象作为子类上转型的接收对象,通过调用子类重写的方法实现目的。
实验总结
实验四第一个
- 很简单
实验四第二个
- 很简单
实验四第三个
- 利用BigDecimal进行四舍五入
实验四第四个
- 如果是基本数据类型的数组,在声明后即可进行有关操作,但如果是引用类型的数组,在声明后要对数组逐个进行实例化后在可以进行操作
实验五第一个
- 无
实验五第二个
- 无
实验五第三个
- ..
实验五第四个
- 利用接口进行数组的比较
- 利用SimpleDateFormat类对实现Date类和String类之间的转换,parse String转变为Date类,format Date类转换成String
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
private Date birthday;
private Date time;
public Employee(String number,String name,String sex,String birthday,String time,Dept dept){
this.number=number;
this.name=name;
this.sex=sex;
try {
this.birthday=sdf.parse(birthday);//parse方法 将字符串变成sdf格式的date类
} catch (ParseException e1) {//处理异常
e1.printStackTrace();
}
try {
this.time=sdf.parse(time);
} catch (ParseException e) {
e.printStackTrace();
}
this.dept=dept;
}
sdf.format(birthday.getTime())//birthday是一个Date类的对象,用Date类的getTime()方法获取时间然后用SimpleDateFormat类的foemat()方法转变成字符串输出