首页 > 代码库 > java的动态绑定与双分派(规避instanceof)
java的动态绑定与双分派(规避instanceof)
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"); }}
执行的结果:
personpersonperson
不管在运行的时候传入的实际类型是什么,它永远都只会执行 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"); }}
结果:
personmanwoman
这种实现方式有一个明显的缺点,它是伪动态的,仍然需要我们来通过程序来判断类型。假如有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"); }}
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。