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方法,就可以喂一类所有动物
(三)代码托管

浙公网安备 33010602011771号