三、读第八、九章

来源:互联网 发布:身份证人脸比对知乎 编辑:程序博客网 时间:2024/05/17 01:34

1、动态绑定或运行时绑定:在运行时根据对象的类型进行绑定。

2、final声明方法:除了防止被覆盖外,更重要的一个功能是可以有效地“关闭”动态绑定,告诉编译器不需要对其进行动态绑定。编译器可以为final生成更有效的代码,但是对整体性能不会有改观的,所以要根据设计决定是否用final,而不是出于试图提高性能的目的使用final.

3、private方法被自动认为是final方法,所以是不能被重写的。

4、关于多态,不是什么都可以发生多态的,只有普通方法调用可以是多态的。

如果是直接访问一个域:

父类:

public class Super {    public int field = 0;    public int getField(){        return field;    }}

子类:

public class Sub extends Super{    public int field = 1;    public int getField(){        return field;    }    public int getSuperField(){        return super.field;    }    public static void main(String[] args) {        Super sup = new Sub();        System.out.println("super.field="+sup.field);//0        System.out.println("super.getField="+sup.getField());//1        Sub sub = new Sub();        System.out.println("sub.field="+sub.field);//1        System.out.println("sub.getField="+sub.getField());//1        System.out.println("sub.getSuperField="+sub.getSuperField());//0    }}

结果是:

//这讲究比较奇怪了super.field=0super.getField=1//下面这个不奇怪sub.field=1sub.getField=1sub.getSuperField=0

正如上面所述,只有普通方法调用才可以是多态,那么父类中的 getField() ,子类中的 getField() 、 getSuperField() 都是普通的方法, 但是 public int field = 1; 和 public int field = 0; 是普通的域,是不具备多态的,所以执行 sup.field 的时候,它虽然是父类指向子类,但是调用的仍然是自己的域,所以答案仍然是0;但是下面调用的方法,其实是多态,调用的是子类的方法,所以值是1.

当然这种情况几乎看不到,因为一般定义属性都是private,根本是无法访问到的。

5、关于静态方法,也不具备多态。只要是调用static 方法,就仍然调用本身,普通方法的话就调用子类的重写方法了。

6、构造器的调用顺序:

调用基类构造器—按声明顺序调用成员的初始化方法—调用导出类构造器的主体

7、关于继承和清理

子类覆盖父类的清理方法的时候,必须在后面调用父类的清理方法。

初始化的顺序是从父类开始初始化,然后子类;但是清理的时候先清理子类,再清理父类。

8、构造器内部的多态方法的行为

问题:如果在一个构造器的内部调用正在构造的对象的某个动态绑定方法,会发生什么?

public class Glyph {    void draw(){        System.out.println("Glyph.draw()");    }    Glyph(){        System.out.println("before deaw()");        draw();        System.out.println("after deaw()");    }}
public class RoundGlyph extends Glyph{    private int radius = 1;    RoundGlyph(int r){        radius = r;        System.out.println("RoundGlyph.RoundGlyph(),radius="+radius);    }    void draw(){        System.out.println("RoundGlyph.draw(),radius="+radius);    }    public static void main(String[] args) {        new RoundGlyph(5);    }}

执行结果是:

before deaw()RoundGlyph.draw(),radius=0  //重点after deaw()RoundGlyph.RoundGlyph(),radius=5

按照顺序,new子类的时候,首先是初始化基类。这里就直接从基类的构造器开始初始化,当执行draw()的时候,由于这个方法是一个动态绑定的方法(子类中有重写),那么它会向外深入到继承层次结构内部,调用子类的方法,那么这个时候会去调用子类中的draw(),因为这个时候radius还没有初始化,那么在类中他默认是0,所以显示出0这句。

所以,要避免这种写法,因为会被覆盖,得出意想不到的结果。

那么从这个程序来看,初始化的实际过程是:

1、在其他任何事情发生之前,将分配给对象的存储空间初始化为二进制的零。2、如前述那样调用基类构造器,调用被覆盖后的draw()方法(在子类的构造器之前使用)3、按照生命的顺序调用成员的初始化方法4、调用导出类的构造器实体

9、第九章:接口和抽象类

这位大神总结的很好: http://blog.csdn.net/chenssy/article/details/12858267

原创粉丝点击