版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chuxue1989/article/details/88209345
java中特性封装和继承都是为了多态服务的
一、定义
多态:动态绑定、后期绑定、运行时绑定。
在编译的时候编译器并不知道该引用的具体类型,只有到运行的是通过该引用知道具体的类型,调用该具体类型的方法。
多态要求必须有某种机制:在运行的时候能判断出对象的类型,他是通过在对象中安置某种“类型信息”
二、多态缺陷
2.1 覆盖私有方法
这个是会产生疑惑的地方,在第七章中fianl修饰方法中也有解释,具体的就是只有非private方法才可以覆盖也就是说private方法不会存在覆盖,更别提多态的发生。这里只要区别对待就行,private方法是属于每个类的,基类和派生类都有相同的private方法,他们是没有关系,这个时候最好不要名字相同。
2.2 字段和静态方法
package com.hfview.defect;
import org.junit.Test;
public class demo {
@Test
public void test(){
A b= new B();
System.out.println(b.count);
b.getCount();
/**
* output:
* 10
* B of this.count:20
* B of super.count:10
*
*/
}
}
class A{
public int count = 10;
public void getCount(){
System.out.println("A of count:"+count);
}
}
class B extends A{
public int count =20;
public void getCount(){
System.out.println("B of this.count:"+this.count);
System.out.println("B of super.count:"+super.count);
}
}
任何的域(字段)都将由编译器解析,因此不是多态的。
就像上面调用b.count编译器缺点b是A类型的,所以b.cont=10;因为方法是可以多态的,所以调用getCount会动态绑定到子类中。通过super可以很方便的访问基类的域信息
尽量不要对基类和派生类的域赋相同的名字,这种做法容易类令人混淆
三、构造器和多态
- 调用基类构造器,这个步骤会不断的反复递归下去,首先是构造这种层次的根,然后是下一层导出类,直到最后的导出类
- 按照生命顺序调用成员的初始化方法
- 盗用导出类的构造函数主体
3.1 构造器内部的多态方法行为
在构造器总调用覆盖的方法。
package com.hfview.constructor;
import org.apache.xmlbeans.impl.xb.xsdschema.Public;
import org.junit.Test;
public class demo1 {
@Test
public void method1(){
B b = new B();
}
}
class A{
void draw(){
System.out.println("A of draw()");
}
public A(){
System.out.println("A constructor invoke:before draw");
draw();
System.out.println("A constructor invoke:after draw");
}
}
class B extends A{
private int count = 1;
void draw(){
System.out.println("B of draw()_count:"+count);
}
public B(){
System.out.println("B constructor invoke");
}
}
一个动态绑定的方法调用会向外深入到继承层次的结构内部,它可以调用导出类的方法。
但是有个缺点,因为在基类中调用导出类的方法,这个时候导出来其实还没有初始化,这个会有问题
所以构造器中应该避免调用多态的方法,如果调用方法调用private的方法