Java第四次作业 李新磊

Java第四次作业--面向对象高级特性(继承和多态)

(一)学习总结

1.学习使用思维导图对Java面向对象编程的知识点(封装、继承和多态)进行总结。

请右键单击查看图像,查看大图

2.阅读下面程序,分析是否能编译通过?如果不能,说明原因。应该如何修改?程序的运行结果是什么?为什么子类的构造方法在运行之前,必须调用父 类的构造方法?能不能反过来?

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();
    }
}
  • 不能通过编译 构造函数的调用必须是构造函数中的第一个语句,子类的构造方法必须先调用父类构造,再执行子类构造

修改为

class Parent extends Grandparent {
    public Parent() {         
    	super("Hello.Grandparent.");
        System.out.println("Parent Created");
    }
}

修改后运行结果

GrandParent Created.String:Hello.Grandparent.
Parent Created
Child Created
  • 子类对象实例化默认调用父类中的构造方法,实例化子类时必须要初始化父类中的属性;不能反过来,父类实例化自己的对象时,不知道自己的子类是谁。

3 . 阅读下面程序,分析程序中存在哪些错误,说明原因,应如何改正?正确程序的运行结果是什么?

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();
    }
}
  • Animal animal = new Dog(); Dog类向上转型为Aniaml类,所调用的sleep方法是被子类覆写的父类方法,而父类中没有sleep()方法.
    animal.sleep();
    改为
class Animal{
  void shout(){
      System.out.println("动物叫!");
  }
  void sleep(){
	  System.out.println("动物睡觉");
  }
}
  • Dog dog = animal;向下转型,需要强制转型,即必须明确指明要转型的子类类型

改为

Dog dog = (Dog)animal;
  • Animal animal2 = new Animal(); 父类引用的对象是父类本身,在向下转型的过程中是不安全的,编译不会出错,但是运行时会出现java.lang.ClassCastException错误。
    dog = (Dog)animal2;

改为

Animal animal2 = new Dog();
        dog = (Dog)animal2;

4.运行下列程序

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
  • 说明 System.out.println(per); p无论有没有调用toString()方法,都输出了类名和地址信息,都会调用object中toString()方法
    System.out.println(per.toString()) ;

toString源码为

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
  • Object 类的 toString 方法返回一个字符串,该字符串由类名(对象是该类的一个实例)、at 标记符“@”和此对象哈希码的无符号十六进制表示组成。

返回值为:getClass().getName() + '@' + Integer.toHexString(hashCode())
Person + @ + 166afb3

(2)那么,程序的运行结果到底是什么呢?利用eclipse打开println(per)方法的源码,查看该方法中又调用了哪些方法,能否解释本例的运行结果?

源码

public void println(Object x) {
        String s = String.valueOf(x);
        synchronized (this) {
            print(s);
            newLine();
        }
    }
valueOf(x)    //if the argument is null, then a string equal to "null"; otherwise, the value of obj.toString() is returned.

如果参数为空字符串,则返回值为空;否则,返回tostring()的返回值。 

(3)在Person类中增加如下方法

public String toString(){ 
        return "姓名:" + this.name + ",年龄:" + this.age ; 
 } 

重新运行程序,程序的执行结果是什么?说明什么问题?

运行结果

姓名:张三,年龄:20
姓名:张三,年龄:20

说明了,子类Person类覆写了Object类中toString()方法

(二)实验总结

1.员工类

程序设计思路

定义员工类为父类,属性为姓名、性别、年龄;定义管理层类,继承员工类,属性为职务、年薪;定义职员类,继承员工类,属性为所属部门、月薪;
定义测试类,输出所有员工的信息。

问题1.子类构造方法的创建

管理层子类(Controller)继承了父类(Employee)的name,sex,age属性,子类自身的属性有:rank(职务),yearmages(年薪)
在子类构造方法运用super关键字,调用父类的构造方法,再为自己的属性赋值

        private String rank;
	private int yearwages;
	public Controller(String name, String sex,int age,String rank,int yearwages){
		super(name,sex,age);
		this.rank=rank;
		this.yearwages=yearwages;
	}

3.图形工具

程序设计思路

设计平面图形抽象类,类中包括求周长和面积的方法、立体图形抽象类,类中包括求表面积和体积的方法;
设计球类、圆柱类,圆锥类,继承立体图形抽象类,设计矩形类、三角形类、圆类,继承平面图形抽象类;
在测试类中分别定义一个球类、圆柱类,圆锥类、矩形类、三角形类、圆类对象,调用计算方法,输出计算结果

问题1.抽象类的继承,子类调用抽象类的方法

平面图形抽象类中包含计算三角形周长面积方法,在三角形子类中直接调用父类的计算方法(Triangle_p(getL1(),getL2(),getL3())),输出计算结果

public abstract class Plane { 
        ...

	public int Triangle_p(int a,int b,int c){        //三角形周长面积计算方法
		return a+b+c;
	}
	public double Triangle_s(int a,int b,int c){
		double p=(a+b+c)/2;
		double s=Math.sqrt(p*(p-a)*(p-b)*(p-c));
		BigDecimal bg = new BigDecimal(s);
		s=bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
		return s; 
	}
}
public class Triangle extends Plane{
	private int l1;
	private int l2;
	private int l3;
	public int getL1() {
		return l1;
	}
	public void setL1(int l1) {
		this.l1 = l1;
	}
	public int getL2() {
		return l2;
	}
	public void setL2(int l2) {
		this.l2 = l2;
	}
	public int getL3() {
		return l3;
	}
	public void setL3(int l3) {
		this.l3 = l3;
	}

	public Triangle(int l1,int l2,int l3){
		this.l1=l1;
		this.l2=l2;
		this.l3=l3;
	}
	public String toString(){            //调用父类的计算方法,输出计算结果
		return "三角形的周长:"+Triangle_p(getL1(),getL2(),getL3())+" 三角形的面积:"+Triangle_s(getL1(),getL2(),getL3());
	}

}

3.动物园

程序设计思路

设计一个动物类,设计狮子、猴子、鸽子类,继承动物类,分别包含eat方法,如果方法被执行,输出信息;
设计一个饲养员类,包含喂食方法(feedLion、feedMonkey、feedPigeon),输出喂食情况。

问题1.在feeder类编写feed方法,实现喂食过程

  • 子类覆写eat()方法
public class Animal {
	public String toString(){
		return "PLACE FEED ME";
	}
}
public class Lion extends Animal {
	public void eat(){
		System.out.println( "FEED LION");
	}

}
  • feed方法,调用三种动物类的eat()方法,输出喂食情况
        public void feedLion(Lion lion){
		lion.eat();
	}
	public void feedMonkey(Monkey[] monkey){
		for(int i=0;i<monkey.length;i++){
		monkey[i].eat();
		}
	}
	public void feedPigeon(Pigeon[] pigeon){
		for(int i=0;i<pigeon.length;i++){
		pigeon[i].eat();
		}
	}

问题2.将Animal改为抽象类,将三种动物类重构,合并feedAnimal(Animal)方法

  • 覆写eat()方法,实现多态
public abstract class Animal {
	public abstract void eat();
}
public class Lion extends Animal {
	public void eat(){
		System.out.print("FEED LION");
	}
}
  • 将Lion、Monkey、Pigeon类向上转型为Animal类
Animal lion = new Lion();
  • 重写feedAnimal方法
public void feedAnimal(Animal animal){
		animal.eat();
	}
  • 修改feedAnimal方法,让它接受一个Animal类数组

将Lion、Monkey、Pigeon类向上转型为Animal类数组

Animal[] lion = {new Lion()};
public void feedAnimal(Animal[] animal){    //接收animal数组
		for(int i=0;i<animal.length;i++){
		animal[i].eat();
		}
	}

问题3.通过本题的重构,说一下多态有什么好处。

第一次重构之前,Animal类从未创建过对象,Animal类只需要充当模板;每种动物都要写一个feed方法,造成代码结构臃肿

第一次重构之后,Animal类为抽象类,各种动物依据它的格式创建对象;Feeder类中各种动物的feed方法合并为一个feedAniaml方法,通过向上转型,将各种动物类转换为Aniaml类,每种动物都使用feedAniaml方法

第二次重构之后,feedAniaml方法接受一个Aniaml类的对象数组,当一种动物有多个对象时,feedAniaml方法就可以接受该对象数组批量执行,只需调用一次feedAniaml方法,就可以喂一类所有动物

(三)代码托管

https://git.oschina.net/hebau_cs15/Java-CS02lxl

posted on 2017-04-15 10:46  押沙龙  阅读(786)  评论(4)    收藏  举报