《java编程思想》这本书被视为java经典,再此总结一些重点知识:
1.java多态性理解
所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
Java中除了static方法和final方法(private方法本质上属于final方法,因为不能被子类访问)之外,其它所有的方法都是动态绑定,这意味着通常情况下,我们不必判定是否应该进行动态绑定—它会自动发生。
final方法会使编译器生成更有效的代码,这也是为什么说声明为final方法能在一定程度上提高性能(效果不明显)。
如果某个方法是静态的,它的行为就不具有多态性:(即子类不能将父类的静态方法重写)
publicclassMain{
publicstaticvoidmain(String[] args){
StaticSuper sup =newStaticSub();
System.out.println(sup.staticGet());
System.out.println(sup.dynamicGet());
}
}
classStaticSuper{
publicstaticStringstaticGet(){//静态方法
return"BasestaticGet()";
}
publicStringdynamicGet(){//未定义,动态方法
return"Base dynamicGet()";
}
}
classStaticSubextendsStaticSuper{
publicstaticStringstaticGet(){//无效的重写
return"Derived staticGet()";
}
publicStringdynamicGet(){
return"Derived dynamicGet()";
}
}
输出结果:BasestaticGet() Derived dynamicGet()
构造函数不具有多态性,他们实际上是static方法,只不过static声明是隐式的。因此构造函数也不能被override
在父类构造函数内部调用具有多态行为的函数将导致无法预测的结果,因为此时子类对象还没初始化,此时调用子类方法不会得到我们想要的结果。
publicclassMain{
publicstaticvoidmain(String[] args){
newRoundGlyph(5);
}
}
classGlyph{
voiddraw(){
System.out.println("Glyph.draw()");
}
Glyph() {
System.out.println("Glyph() before draw()");//1.先执行父类的构造方法
draw();//在父类构造函数内部调用具有多态行为的函数 //2.执行override之后的方法
System.out.println("Glyph() after draw()");//3.按顺序执行
}
}
classRoundGlyphextendsGlyph{
privateintradius =1;
RoundGlyph(intr) {
radius = r;
System.out.println("RoundGlyph.RoundGlyph(). radius = "+ radius);//4.最后执行子类的构造方法
}
voiddraw(){
System.out.println("RoundGlyph.draw(). radius = "+ radius);
}
}
结果:
Glyph() before draw()
RoundGlyph.draw(). radius = 0
Glyph() after draw()
RoundGlyph.RoundGlyph(). radius = 5
##讲真的这个结果足够出人意料,想知道形成这个结果的原因,首先得明确构造函数的调用顺序:
(1)在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制0;
(2)调用(父类)基类构造函数。从根开始递归下去,因为多态性此时调用子类覆盖后的draw()方法(要在调用RoundGlyph构造函数之前调用),由于步骤1的缘故,我们此时会发现radius的值为0;
(3)按声明顺序调用成员的初始化方法;
(4)最后调用子类的构造函数。
显而易见,如果在父类的构造函数函数中调用多态的方法,创建子类对象时会先从父类构造方法开始执行,并且执行的是重写过后的方法。
只有非private方法才可以被覆盖(override),但是还需要密切注意覆盖private方法的现象,这时虽然编译器不会报错,但是也不会按照我们所期望的来执行,即覆盖private方法对子类来说是一个新的方法而非重载方法。因此,在子类中,新方法名最好不要与基类的private方法采取同一名字(虽然没关系,但容易误解,以为能够覆盖基类的private方法)。
Java类中属性域的访问操作都由编译器解析,因此不是多态的。父类和子类的同名属性都会分配不同的存储空间.如果子类要使用父类中的属性,须super.+属性