java动态/静态绑定以及双分派

动态绑定:程序在运行期间而不是在编译期间,根据所引用对象的实际类型调用对应的方法,重写以及接口的实现都属于该范畴,使用实际的对象信息来完成API的调用

public class DynamicBind {

    public static void main(String[] args) {
        Father f = new Father();
        f.method();

        f = new Son();
        f.method();

        f = new Daughter();
        f.method();
    }
}

class Father {
    public void method() {
        System.out.println("Father.method");
    }
}

class Son extends Father{
    public void method() {
        System.out.println("Son.method");
    }
}

class Daughter extends Father{
    public void method() {
        System.out.println("Daughter.method");
    }
}
output

Father.method
Son.method
Daughter.method

尽管引用的类型都是Father,但是在运行时却调用的是实际类型的方法,也就是说父类引用指向子类实例时,会根据实际实例类型调用对应的方法

静态绑定:在编译期间已经确定执行的方法,API的重载属于该范畴,也就是说需要执行的方法在编译期间已经确定。凡是使用staticprivatefinal修饰的方法或者属性也属于该范畴,static修饰的方法或者属性属于类,不能被继承也就是说无法重写。private只有该类的对象能够访问,不能被继承也就是说无法重写,final修改的属性不允许重新复制,可以理解为常量,final修饰的方法不允许被重写。使用类信息完成API的调用

public class StaticBind {
    public static void main(String[] args) {
        Ext ext = new Ext();

        Mother m = new Mother();
        ext.method(m);

        m = new Tom();
        ext.method(m);

        m = new Mark();
        ext.method(m);

    }
}

class Mother{}
class Tom extends Mother{}
class Mark extends Mother{}

class Ext {
    public void method(Mother mother) {
        System.out.println("Mother.method");
    }

    public void method(Tom tom) {
        System.out.println("Tom.method");
    }

    public void method(Mark mark) {
        System.out.println("Mark.method");
    }
}
output

Mother.method
Mother.method
Mother.method

编译时通过方法签名已经确定调用的方法,也就是说在实际调用中传入了不同的对象信息,但是实际的类信息只有一个就是Mather


伪动态实现(instanceof采用类型判断的方式实现重载的动态效果

class Ext {
    public void method(Mother mother) {
        if (mother instanceof Tom) {
            System.out.println("Tom.method");
        } else if (mother instanceof Mark) {
            System.out.println("Mark.method");
        } else if (mother instanceof Mother) {
            System.out.println("Mother.method");
        }
    }

    public void method(Tom tom) {
        System.out.println("Tom.method");
    }

    public void method(Mark mark) {
        System.out.println("Mark.method");
    }
}
父类的判断必须要写在最后,这个后和异常捕获的道理时一致的,如果将父类写在最前边,那么和之前的运行效果时一致的,因为自类和父类是is-a的关系。双分派实现动态绑定

public class DispatchBind {
    public static void main(String[] args){
        Execute exe = new Execute();

        Mom mom = new Mom();
        mom.accept(exe);

        mom = new Jack();
        mom.accept(exe);


        mom = new Licy();
        mom.accept(exe);
    }
}

class Mom{
    public void accept(Execute execute) {
        execute.method(this);
    }
}

class Jack extends Mom{
    public void accept(Execute execute) {
        execute.method(this);
    }
}

class Licy extends Mom{
    public void accept(Execute execute) {
        execute.method(this);
    }
}

class Execute {
    public void method(Mom Mom) {
        System.out.println("Mom.method");
    }

    public void method(Jack jack) {
        System.out.println("Jack.method");
    }

    public void method(Licy licy) {
        System.out.println("Licy.method");
    }
}
output

Mom.method
Jack.method
Licy.method
双分派实现动态绑定的本质,就是在重载方法委派的前面加上了继承体系中重写的环节,由于重写是动态的,所以重载就是动态的了

第一次分派:mom = new Jack();mom.accpet(ext);父类引用指向自类实例,并且自类重写了父类方法所有会调用自类Jack的accpet()方法

第二次分派:发生在Jack类中的accpet中,关键子为this。该处的this可以理解为Jack.this.此时会调用Execute中的method(Jack jack)

双分派意味着请求的操作取决于请求的种类和接受者的类型

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值