习题解答chapter04
题目:
- 实验:利用IDE的debug功能给例6.4和例6.6的new语句设置断点,使用单步调试(step into/step over)跟踪子类对象实例化(初始化)的执行顺序,并总结该过程。(教材:Java面向对象程序设计,第二版,袁绍欣主编)
- 如何实现两个对象之间互发消息,请举例说明。
- 谈谈组合与继承的区别以及两者的使用场景(即什么时候宜用组合?什么时候宜用继承? )。
- Java中的运行时多态的含义是什么?有什么作用?请举例说明。
- 使用接口改写例6.8中的程序。
- 简述运算符instanceof的使用场景。
1. 实验:利用IDE的debug功能给例6.4和例6.6的new语句设置断点,使用单步调试(step into/step over)跟踪子类对象实例化(初始化)的执行顺序,并总结该过程。
下面给出6.4调试动图(大小限制,该动图尺寸不大)
下面给出6.6调试动图
程序说明:
package bookcode.ex6.part6_6; class Pare { int i = 3; Pare() { super(); } }; class Construct extends Pare { int i = 8; Construct() { } Construct(int num) { this(); } public static void main(String args[]) { Construct ct = new Construct(9); System.out.println(ct.i); System.out.println(ct.getSuper()); } int getSuper() { return super.i; } }
先执行的是子类的this(),Construct()中有一个隐含的super(),使得类Construct在生成对象时,父类 i=3 显式初始化能够执行。
实例化执行顺序总结:
- 为子类对象分配内存空间,对域变量进行默认初始化。
- 绑定构造方法,将new对象中的参数传递给构造方法的形式参数。
- 调用this或super语句,二者必居其一,也只有一。
- 进行实例变量的显式初始化操作。
- 执行当前构造方法体中的程序代码。
2. 如何实现两个对象之间互发消息,请举例说明。
使用引用的属性或方法其实都是调用对象的属性或方法,而消息概念的引入就是为了说明这样的过程。消息的实质就是引用向对象发出的服务请求,是对数据成员和成员方法的调用。下面列举能否发送消息的三个条件:
- 引用必须真实引用了特定的对象,否则会抛出NullPointerException异常。
- 访问对象必须定义了相应的属性或方法,否则编译不会通过。
- 被访问的属性或方法必须具有可访问的权限。
消息也就是相当于在遥控器和显示器之间架起沟通的桥梁。在面向对象语言中,消息把不同对象相互联系起来,共同完成特定功能。
实例代码:
class FighterPlane { String name; int missileNum; public FighterPlane(String _name, int _missleNum) { this.name = _name; this.missileNum = _missleNum; } public void fire() { if (this.missileNum > 0) { System.out.println("now fire a missile !"); this.missileNum -= 1; } else { System.out.println("No missile left !"); } } } class A { FighterPlane fp; public A(FighterPlane fpp) { this.fp = fpp; //A对象中拥有了FighterPlane对象的引用 } public void invoke() { //A对象发送消息给FighterPlane的对象 System.out.println(fp.name); } }public class Run { public Run() { } public static void main(String[] var0) { FighterPlane ftp = new FighterPlane("su35", 10); //产生A对象,并将ftp作为对象引用传入 A a= new A(ftp); a.invoke(); } }
3. 谈谈组合与继承的区别以及两者的使用场景(即什么时候宜用组合?什么时候宜用继承? )。
- 组合:通过对象内部的属性引用来实现。使对象之间的耦合性较为松散。
- 继承:从已有的类派生出新的类。在不同的类中也可能会有共同的特征和动作,可以把这些共同的特征和动作放在一个类中,让其它类共享。因此可以定义一个通用类,然后将其扩展为其它多个特定类,这些特定类继承通用类中的特征和动作。继承是 Java 中实现软件重用的重要手段,避免重复,易于维护,易于理解。
- 组合就像房间里面的窗户、墙壁、地板、桌子、椅子等,他们之间并不存在结构上的相似性,只是功能上组合可以发挥更大的作用,但是单独是可以独立运行的。继承就像对房间进行拓展成为一栋楼,前面的零部件它都具备,但是如果没有房间,大楼是无法构建的,具有结构和功能上的关联。
- 显而易见,在不具有结构和功能上的相似性时,使用继承可以减少代码重复率,易于维护;在结构实现不同、功能“可叠加”时,使用组合无疑是优于继承的。
4. Java中的运行时多态的含义是什么?有什么作用?请举例说明。
Java提供了两种多态机制——重载和覆盖。运行时多态指的是覆盖,在运行时根据输入参数动态选择不同的 成员方法执行,体现了一个类本身的多态性,使代码具有良好的拓展性。
举例:同样的红烧鱼,厨师老师的红烧方法传给厨师徒弟后,厨师徒弟在红烧方法上做了改动,这是红烧方法的重写,就相当于 java 的方法重写。
重写代码如下:
class Ct{ void hongshao(int a){ System.out.println("这是厨师老师的红烧int的方法"); } } class Cs extends Ct{ void hongshao(int a) { System.out.println("这是厨师徒弟的红烧int的方法"); } }
重载代码如下:
class Cs extends Ct{ void hongshao(int a) { System.out.println("这是厨师徒弟的红烧int的方法"); } void hongshao(float b) { System.out.println("这是厨师徒弟红烧float的方法"); } void hongshao(int a,float b) { System.out.println("这是厨师徒弟红烧int和float的方法"); } }
5. 使用接口改写例6.8中的程序。
创建接口
package bookcode.ex6.part6_8; public interface Shape { double getArea(); double getPerimeter(); void show(); }
圆类
package bookcode.ex6.part6_8; public class Circle implements Shape{ private int r; public Circle(int _r){ r = _r; } @Override public double getArea() { return r * r * Math.PI; } @Override public double getPerimeter() { return 2 * Math.PI * r; } @Override public void show() { System.out.println("Circle Area:" + getArea()); System.out.println("Circle Perimeter:" + getPerimeter()); } }
矩形类
package bookcode.ex6.part6_8; public class Rect implements Shape { private int k; private int m; public Rect(int width, int height) { k = width; m = height; } public double getArea() { return (k * m); } public double getPerimeter() { return (2 * k + 2 * m); } @Override public void show() { System.out.println("Rect Area:" + getArea()); System.out.println("Rect Perimeter:" + getPerimeter()); } }
三角形类
package bookcode.ex6.part6_8; import com.sun.tools.javac.file.SymbolArchive; public class Triangle implements Shape{ private int x, y, z, m; public Triangle(int _x, int _y, int _z){ x = _x; y = _y; z = _z; m = (x + y +z) / 2; } @Override public double getArea() { return (Math.sqrt(m *(m - x) * (m - y) * (m - z))); } @Override public double getPerimeter() { return 2 * m; } @Override public void show() { System.out.println("Triangle Area:" + getArea()); System.out.println("Triangle Perimeter:" + getPerimeter()); } }
运行
package bookcode.ex6.part6_8; public class RunShape{ public static void main(String args[]){ Rect rect = new Rect(5 , 6); Triangle triangle = new Triangle(3, 4, 5); Circle circle = new Circle(5); rect.show(); System.out.println(); triangle.show(); System.out.println(); circle.show(); } }
6. 简述运算符instanceof的使用场景。
instanceof 是 Java 的一个二元操作符,instanceof 是 Java 的保留关键字。它的作用是测试它左边的对象是否是它右边的类或子类的实例,返回 boolean 的数据类型。
package bookcode.ex6.part6_15; class Uncle{} class Pare{} class Pare1 extends Pare{} class Pare2 extends Pare1{} public class InstanceofTest { public static void main(String args[]) { Uncle uncle = new Uncle(); Pare pare = new Pare(); Pare1 pare1 = new Pare1(); Pare2 pare2 = new Pare2(); //验证pare if (pare instanceof Pare) { System.out.println("pare instanceof Pare"); } if (!(pare instanceof Pare1)){ System.out.println("pare not instanceof Pare1"); }else if (pare instanceof Pare1){ System.out.println("pare instanceof Pare1"); } if(!(pare instanceof Pare2)){ System.out.println("pare not instanceof Pare2"); }else if (pare instanceof Pare2){ System.out.println("pare instanceof Pare2"); } System.out.println(); //验证pare1 if (pare1 instanceof Pare1) { System.out.println("pare instanceof Pare"); } if (!(pare1 instanceof Pare)){ System.out.println("pare1 not instanceof Pare"); }else if(pare1 instanceof Pare){ System.out.println("pare1 instanceof Pare"); } if(!(pare1 instanceof Pare2)){ System.out.println("pare1 not instanceof Pare2"); }else if(pare1 instanceof Pare2){ System.out.println("pare1 instanceof Pare2"); } System.out.println(); //验证pare2 if (pare2 instanceof Pare2) { System.out.println("pare instanceof Pare"); } if (!(pare2 instanceof Pare)){ System.out.println("pare2 not instanceof Pare"); }else if (pare2 instanceof Pare){ System.out.println("pare2 instanceof Pare"); } if(!(pare2 instanceof Pare1)){ System.out.println("pare2 not instanceof Pare1"); }else if (pare2 instanceof Pare1){ System.out.println("pare2 instanceof Pare1"); } System.out.println(); //验证uncle if (uncle instanceof Uncle){ System.out.println("uncle instanceof Uncle"); } // 语法错误,无法编译通过 /* if (uncle instanceof Pare) { System.out.println("uncle instanceof Pare"); }else { System.out.println("uncle instanceof Pare"); } if (!(uncle instanceof Pare1)){ System.out.println("uncle not instanceof Pare1"); }else { System.out.println("uncle instanceof Pare1"); } if(!(uncle instanceof Pare2)){ System.out.println("uncle not instanceof Pare2"); }else { System.out.println("uncle instanceof Pare2"); } */ } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!