1. 实验:利用IDE的debug功能给例6.4和例6.5的new语句设置断点,使用单步调试(step into/step over)跟踪子类对象实例化(初始化)的执行顺序,并总结该过程。
//例6.4:显式使用super调用父类的构造方法
class AddClass {
private int x=0,y=0,z=0;
AddClass (int x) {
this.x=x;
}
AddClass (int x,int y) {
this(x);
this.y=y;
}
AddClass (int x,int y,int z) {
this(x,y);
this.z=z;
}
public int add() {
return x+y+z;
}
}
public class SonAddClass extends AddClass{
int a=0,b=0,c=0;
SonAddClass (int x) {
super(x); a=x+7;
}
SonAddClass (int x,int y){
super(x,y); a=x+5; b=y+5;
}
SonAddClass (int x, int y,int z){
super(x,y,z); a=x+4; b=y+4; c=z+4;
}//super(x,y,z)如果去掉会如何?
public int add() {
System.out.println("super:x+y+z="+super.add());
return a+b+c;
}
public static void main(String[] args){
SonAddClass p1=new SonAddClass (2,3,5);
SonAddClass p2=new SonAddClass (10,20);
SonAddClass p3=new SonAddClass (1);
System.out.println("a+b+c="+p1.add());
System.out.println("a+b="+p2.add());
System.out.println("a="+p3.add());
}
}
//例6.5:隐式使用super调用父类的构造方法
class Pare {
int i=3;
Pare(){
System.out.println("call super()");
}
}
class Construct extends Pare {
int i = 10;
Construct() {
System.out.println("execute Construct()");
}
Construct(int num) {
this(); //如果去掉此句呢?
System.out.println("execute Construct(int)");
}
public static void main(String[] args) {
Construct ct = new Construct(9);
System.out.println(ct.i);
}
}
call super()
execute Construct()
execute Construct(int)
10
(1)为子类对象分配内存空间,对成员变量进行默认的初始化
(2)绑定子类构造方法,将new中的参数传递给构造方法的形式参数。
(3)显式或隐式调用super语句, 对从父类继承来的实例变量进行初始化。
(4)按定义顺序执行实例变量初始化操作。 执行子类构造方法的剩余代码。
2. 如何实现两个对象之间互发消息,请举例说明。
)引用必须真实引用了特定的对象。
2)被访问对象必须定义了相应的属性或方法。
3)被访问的属性或方法必须具有可访问的权限。
class FighterPlane{
String name;
int missileNum;
public FighterPlane(String _name,int _missileNum){
name = _name;
missileNum = _missileNum;
}
public void fire(){
if (missileNum>0){
System.out,println("now fire a missile !");
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 static void main(String[] args)
{
FighterPlane ftp = new FighterPlane("su35",10);
//产生A对象,并将ftp对象引用作为参数传入
A a = new A(ftp);
//发送消息,产生调用关系
a.invoke();
}
}
3. 谈谈组合与继承的区别以及两者的使用场景(即什么时候宜用组合 ?什么时候宜用继承?)。
组合:在新的类中产生现有类的对象。由于新的类是由现有类的对象所组成,所以这种方法称为组合。该方法只是复用了现有程序代码的功能,而非它的形式。
继承:按照现有的类型来创建新类。无需改变现有类的形式,采用其形式并在其中添加新代码。这种方式称为继承。
当要设计的新类与原有的类的关系是“has-a”(有一个)时,适合用组合的方式。
例如,一个简单的房子(SimpleHouse)有两个窗户(Window)、有一个门(Door)、有一个桌子(Table)以及四个椅子(Chair)等等,可以用如下代码描述:
//: SimpleHouse.java
public class SimpleHouse {
private Window[] windows = new Window[2];
private Door door = new Door();
private Table table = new Table();
private Chair[] chairs = new Chair[4];
/*some code...*/
}
class Window {/*some code...*/}
class Door {/*some code...*/}
class Table {/*some code...*/}
class Chair {/*some code...*/}
//:~插入代码片
*当要设计的新类原有的类的关系是“is-a”时,适合用组合的方式。
*例如,狗是一个宠物,猫是一个宠物,而宠物是一个原有的类,可以用如下代码描述。
//: Pet.java
2 abstract public class Pet {
3 public void jump() {
4 System.out.println(this.getClass().getSimpleName()+" jump");
5 }
6 abstract public void say();
7 /*some code...*/
8 }
9
10 class Dog extends Pet {
11 @Override
12 public void say() {
13 System.out.println("woof!");
14 }
15 /*some code...*/
16 }
17
18 class Cat extends Pet {
19 @Override
20 public void say() {
21 System.out.println("meow~");
22 }
23 /*some code...*/
24 }
25 //:~
4. Java中的运行时多态的含义是什么?有什么作用?请举例说明。
通过方法覆盖实现(子类覆盖父类方法)。可以进行动态绑定,使用父类引用指向子类对象,再调用某一父类中的方法时,不同子类会表现出不同结果。这样做的作用就是拓展性极好。
//假设有一个类 叫 鸟类,它拥有属性翅膀,拥有方法鸣叫,如下
public class Bird{
private Wing wing;
public void moo(){
System.out.println("鸟叫声");
}
}
/*鸟类封装了 翅膀类和moo方法;另外有两个类都继承鸟类并重写了moo方法,分别是鹦鹉和麻雀如下:*/
//鹦鹉类:
public class Parrot extends Bird{
public void moo(){
System.out.println("鹦鹉的叫声");
}
}
//麻雀类:
public class Sparrow extends Bird{
public void moo(){
System.out.println("麻雀的叫声");
}
}
/*然后你有个妻子她想听鸟叫,就有个妻子类*/
public class Wife{
public void listen(Bird bird){
bird.moo();
}
/*这时多态就很好的体现了,你妻子想听鸟叫,无论什么鸟都可以给她,但是你想让她和鹦鹉说话,你就买了一只鹦鹉传给listen方法,结果你妻子听到了鹦鹉的叫声,程序输出:鹦鹉的叫声
*/
public static void main(String[] args) {
new Wife().listen(new Parrot());
}
}
/*多态实现了动态绑定,让程序有了很好的扩展性,比如你以后想买一只燕子送给你妻子,就只需要写个燕子类Swallow继承Bird方法就可以了,而不需要再在妻子类里添加一个方法listen(Swallow swallow) */
5. 使用接口改写例6.8中的程序。
//Shapes接口
2 package runshape;
3
4 public interface Shapes {
5 public double getArea();
6 public double getPerimeter();
7 public void show();
8 }
圆形类
1 package runshape;
2
3 public class Circle implements Shapes{
4 private int r;
5 public Circle(int r){
6 this.r=r;
7 }
8
9 public double getArea() {
10 return Math.PI*Math.pow(r, 2);
11 }
12 public double getPerimeter(){
13 return 2*Math.PI*r;
14 }
15
16 public void show(){
17 System.out.println("圆形:");
18 System.out.println("圆的面积是"+this.getArea());
19 System.out.println("圆的周长是"+this.getPerimeter());
20 }
21 }
矩形类
1 package runshape;
2
3 public class Rect implements Shapes{
4 private int height;
5 private int width;
6 public Rect(int height, int width){
7 this.height=height;
8 this.width=width;
9 }
10 public double getArea(){
11 return height*width;
12 }
13 public double getPerimeter(){
14 return 2 * height + 2 * width;
15 }
16 public void show(){
17 System.out.println("矩形:");
18 System.out.println("矩形的面积是"+this.getArea());
19 System.out.println("矩形的周长是"+this.getPerimeter());
20 }
21
22 }
三角形类
1 package runshape;
2
3 public class Triangle implements Shapes {
4 private int x;
5 private int y;
6 private int z;
7 public Triangle(int x, int y, int z){
8 this.x=x;
9 this.y=y;
10 this.z=z;
11 }
12
13 @Override
14 public double getArea() {
15 double m=(x+y+z)/2.0;
16 return Math.sqrt(m*(m-x)*(m-y)*(m-z));
17 }
18
19 @Override
20 public double getPerimeter() {
21 return x+y+z;
22 }
23
24 public void show(){
25 System.out.println("三角形:");
26 System.out.println("三角形的面积是"+this.getArea());
27 System.out.println("三角形的周长是"+this.getPerimeter());
28 }
29
30 }
打印
1 package runshape;
2
3 public class RunShape {
4 public static void print(Shapes s){
5 s.show();
6 }
7 public static void main(String[] args) {
8 Rect rect=new Rect(25,25);
9 Triangle triangle=new Triangle(5,5,8);
10 Circle circle=new Circle(12);
11
12 //打印输出
13 print(rect);
14
15 print(triangle);
16
17 print(circle);
18 }
19
20
21 }
6. 自定义一个类,覆写equals方法,以满足自身业务需求
用instanceof判断一个对象是不是某个类或者其子类的实例,还可以将这个对象强制转换成这个类的类型。
public class Test {
static class A{ }
static class B extends A{ }
public static void main(String[] args) {
A a = new A();
B b = new B();
System.out.println( "a instanceof A 的结果:" + ( a instanceof A ) );
System.out.println( "b instanceof A 的结果:" + ( b instanceof A ) );
System.out.println();
System.out.println( "a instanceof B 的结果:" + ( a instanceof B ) );
System.out.println( "b instanceof B 的结果:" + ( b instanceof B ) );
System.out.println();
/*
注意:
下面用Object类对象引用某个类实例 是实际应用中非常常见的
object instanceof class ,如果object 实际引用的对象实例 是 class 的实例对象
或者 class 的子类实例对象,则返回true
注意 “实际引用的对象实例” 这个词强调的'实际引用'.
*/
Object o = new A();
System.out.println( "o instanceof A 的结果:" + ( o instanceof A ) );
System.out.println( "o instanceof B 的结果:" + ( o instanceof B ) );
System.out.println();
o = new B();
System.out.println( "o instanceof A 的结果:" + ( o instanceof A ) );
System.out.println( "o instanceof B 的结果:" + ( o instanceof B ) );
System.out.println();
}
}
7. 举例说明运算符instanceof的使用场景。
instanceof:二元运算符。
用法:boolean result = object instanceof class 判断对象是否为特定类的实例
在程序的运行多态中,即用父类或接口的引用去引用子类、实现类的对象时,我们想知道父类或接口的引用所引用的对象是否是某一个具体类的对象时,我们就可以用instanceof,避免向下转型抛出运行时异常。
也可以用来判断两类是否存在父类与子类的关系
例子:
Shape s = new Rect(10,30);//父类声明引用子类实例,向上转型
s = new Triangle(5,5,8);
s = new Circle(12.5);
java.lang.ClassCastException: Circle cannot be cast to Triangle
//Triangle triangle =(Triangle)s //向下转型抛出运行时异常
//triangle.drawTri();
if(s instanceof Rect){ //避免向下转型抛出运行时异常
Rect rectangle = (Rect)s;
rectangle.drawRect();
} else if (s instanceof Triangle){
Triangle triangle =(Triangle)s;
triangle.drawTri();
} else if (s instanceof Circle){
Circle circle = (Circle) s;
circle.drawCir();
}
8. 谈谈抽象类与接口的异同以及两者的使用场景。
异同如下图:
使用场景:
抽象类:抽象类在被继承时体现的是is-a关系。一般是有继承关系,但父类和子类以及各个子类之间对某些方法的实现又不同。
接口:接口在被实现时体现的是can-do关系。一般是把多个类的相同功能抽象出来,类之间没有继承关系。