首页 » 技术分享 » 多态&动态绑定&方法匹配&方法绑定

多态&动态绑定&方法匹配&方法绑定

 

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 DB 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类开始的





转载自原文链接, 如需删除请联系管理员。

原文链接:多态&动态绑定&方法匹配&方法绑定,转载请注明来源!

0