1)多态:父类型的变量,可以引用子类型的对象
class A{
}
class B extends A{
}
那么可以 A a = new B(); 其中这里的A叫做声明类型,B叫做实际类型
那么这里的a就可以调用B中的方法(如果有的话),那么是不是什么方法都能调用呢?往下看
2)动态绑定
定义:如果一个方法在父类中定义,在子类中重写,那么这个方法的调用是由实际类型决定的。这就是动态绑定
例子:
class A{
public void f(){
System.out.println("AAA");
}
}
class B extends A{
public void f(){
System.out.println("BBB");
}
public void m(){
System.out.println("MMM");
}
}
那么 A a = new B(); a.f(); 结果是输出BBB。。因为实际类型是B
注意:看清楚动态绑定的前提,一个方法在父类中定义,在子类中重写。
a.m()会出错,原因是父类里面根本没有这个方法,只是在子类里有。
那么多态调用方法具体原理是什么呢?往下看
3)方法匹配
定义:调用方法时,引用变量的声明类型,决定了编译时匹配哪个类的哪个方法
例子:上面的a.m(),由于a的声明类型是A,所以在类A里面找m()这个方法,发现没有,自然就出错了。
那要是有这个方法呢,为什么又调用了子类的方法?这就要说到方法绑定了
4)方法绑定
定义:也就是上面的动态绑定。是在运行时实现的。
也就是说编译时,方法匹配决定匹配声明类型中的哪个方法;运行时,去看看这个方法在实际类型中是不是重写了,重写了就调用实际类型的这个方法,不然就声明类型的那个方法
例子:解释上面的a.f()的过程。
首先a的声明类型是A,那么编译时去A这个类里面找f()方法,找到了,那么编译通过
然后运行时,发现a的实际类型是B,那么去B这个类里面看看有没有重写f()这个方法。有。好,就用B的f()
所以输出BBB
5)一个大例子,全对的话,那么多态你就搞懂了
public class A {
public String s = "123";
public void show(A obj){
System.out.println("A and A");
}
public void show(D obj){
System.out.println("A and D");
}
}
class B extends A{
public String s = "456";
public void show(A obj){
System.out.println("B and A");
}
public void show(B obj){
System.out.println("B and B");
}
public void show(E obj){
System.out.println("B and E");
}
}
class C extends B{
}
class D extends B{
}
class E{
}
public class Test {
public static void main(String[] args){
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
E e = new E();
a1.show(b);
a1.show(c);
a1.show(d);
System.out.println(a1.s);
a2.show(b);
a2.show(c);
a2.show(d);
//a2.show(e);//这句编译不过
System.out.println(a2.s);
b.show(b);
b.show(c);
b.show(d);
b.show(e);
System.out.println(b.s);
}
}
5.1)结果是什么呢?
A and A
A and A
A and D
123
B and A
B and A
A and D
123
B and B
B and B
A and D
B and E
456
5.2)解释
5.2.1)String s = "123"; String s = "456"; 是为了验证变量是由什么类型决定的。。。可以看到变量是由声明类型决定
5.2.2)前三个输出(A and A,A and A,A and D),很正常,最多涉及一个函数参数的自动类型转换(子类自动转父类),没什么说的。
5.2.3)中间三个输出(B and A,B and A,A and D),先是在类A里面进行方法匹配,运行时再到类B里面看看有没有重写,发现只有一个public void show(A obj)重写了,那么就只有这个方法是调用B的方法,其他都调用A的方法
5.2.4)后面四个输出(B and B,B and B,A and D,B and E),我们只解释A and D为什么。由于继承的原因,其实A中的非private方法都被B继承了,所以B自己找不到方法的,会去父类A里找。
所以才会有A and D这个输出
5.3)再来看看那句,被注释的,编译不过的
a2.show(e);//这句编译不过
5.3.1)原因呢?编译阶段,方法匹配不成功。因为A里面没有 show(E obj)的,而且也没有show(O obj)的。(其中O是E的父类型)
5.3.2)那么怎样才能编译通过呢?
没办法,只好转回实际类型:B a2 = (B)a2; a2.show(e)就没问题了
那我不想转成实际类型怎么办呢? ((B)a2).show(e)也行
6)来点书上的判断对错题
前提Number是Double、Integer等类型的父类
6.1)
Number numberRef = new Integer(0);
Integer IntegerRef = (Integer)numberRef;
可行,原因是numberRef的实际类型本来就是Integer,转换回去当然可以
6.2)
Number numberRef = new Integer(0);
Double DoubleRef = (Double)numberRef;
不行,编译能通过,但是运行会出错。原因是Integer类型和Double类型不能相互转换。要想转换,那么先转成数值,再转换。也就是Double DoubleRef = new Double(numberRef.doubleValue());
6.3)
Number x = new Integer(3);
x.compareTo(new Integer(4));
不行,编译不能通过。原因是Number里面没有compareTo方法,虽然Integer里面有。。但是上面讲的很清楚了,方法匹配是从Number类开始的
转载自原文链接, 如需删除请联系管理员。
原文链接:多态&动态绑定&方法匹配&方法绑定,转载请注明来源!