1. 动态绑定的概念
指程执行期间(而不是在编译期间)判断所引用对象的实际类型,根据其实际的类型调用其相应的方法 .
例如:
package org.demo.clone.demo; public class DynamicBound { public static void main(String[] args) { Person person = new Man() ; person.say() ; } } class Person{ public void say(){} ; } class Man extends Person{ public void say(){ System.out.println("Hey Man"); } }
结果:
Hey Man
调用的是Person对象中的say方法 但是实际执行的是Man中的方法,这就是动态绑定。 在java语言中,继承中的覆盖就是是动态绑定的,当我们用父类引用实例化子类时,会根据引用的实际类型调用相应的方法
2. 静态绑定
静态绑定就是指在编译期就已经确定执行哪一个方法。方法的重载(方法名相同而参数不同)就是静态绑定的,重载时,执行哪一个方法在编译期就已经确定下来
package org.demo.demo; public class StaticBound { public static void main(String[] args) { OutputName out = new OutputName() ; Person p = new Person() ; Person man = new Man() ; Person woman = new Woman() ; out.print(p) ; out.print(man) ; out.print(woman) ; } } class Person{ } class Man extends Person{ } class Woman extends Person{ } class OutputName{ void print(Person p){ System.out.println("person"); } void print(Man m){ System.out.println("man"); } void print(Woman w){ System.out.println("woman"); } }
执行的结果:
person
person
person
不管在运行的时候传入的实际类型是什么,它永远都只会执行 void print(Person p)这个方法,即 : 重载是静态绑定的
如果希望使用重载的时候,程序能够根据传入参数的实际类型动态地调用相应的方法,也就是说,我们希望java的重载是动态的,而不是静态的。
但是由于java的重载不是动态绑定,只能通过程序来人为判断,我们一般会使用instanceof操作符来进行类型的判断 代码如下:
package org.demo.demo; public class StaticBound { public static void main(String[] args) { OutputName out = new OutputName() ; Person p = new Person() ; Person man = new Man() ; Person woman = new Woman() ; out.print(p) ; out.print(man) ; out.print(woman) ; } } class Person{ } class Man extends Person{ } class Woman extends Person{ } class OutputName{ void print(Person p){ if(p instanceof Man) print((Man)p); else if (p instanceof Woman) print((Woman)p); else System.out.println("person"); } void print(Man m){ System.out.println("man"); } void print(Woman w){ System.out.println("woman"); } }
结果:
person
man
woman
这种实现方式有一个明显的缺点,它是伪动态的,仍然需要我们来通过程序来判断类型。假如有100个子类的话,还是这样来实现显然是不合适的
必须通过其他更好的方式实现才行,我们可以使用双分派方式来实现动态绑定
3. 使用双分派实现动态绑定
什么是双分派:
package org.demo.demo; /** * 双分派 */ public class DoubleAssign { public static void main(String[] args) { A a = new A() ; a.method02(new B()) ; } } class A { public void method01(){ System.out.println("\t method01"); } public void method02(B b ){ b.classMethod01(this) ; } } class B{ public void classMethod01(A a ){ System.out.println("------classMethod01 start----- "); a.method01(); System.out.println("------classMethod01 end----- "); } }
通过双分派实现动态绑定
package org.demo.demo.foo; /** * 通过双分派实现动态绑定 */ public class DoubleAssignForDynamicBound { public static void main(String[] args) { OutputName out = new OutputName() ; Person p = new Person() ; Person man = new Man() ; Person woman = new Woman() ; p.accept(out) ; man.accept(out) ; woman.accept(out) ; } } class Person{ public void accept(OutputName out) { out.print(this) ; } } class Man extends Person{ public void accept(OutputName out) { out.print(this) ; } } class Woman extends Person{ public void accept(OutputName out) { out.print(this) ; } } class OutputName{ void print(Person p){ System.out.println("person"); } void print(Man m){ System.out.println("man"); } void print(Woman w){ System.out.println("woman"); } }