zoukankan      html  css  js  c++  java
  • 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");
        }
    }
    
     

    执行的结果: 

    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("	 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");
        }
    }
    
     
  • 相关阅读:
    第一章
    第三章
    第四章
    第十章 读书笔记
    第八章 读书笔记
    第九章 读书笔记
    第7章实验心得
    第六章实验心得
    第五章心得体会
    第四章实验心得
  • 原文地址:https://www.cnblogs.com/liaokailin/p/3804437.html
Copyright © 2011-2022 走看看