动态绑定:程序在运行期间而不是在编译期间,根据所引用对象的实际类型调用对应的方法,重写以及接口的实现都属于该范畴,使用实际的对象信息来完成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的重载属于该范畴,也就是说需要执行的方法在编译期间已经确定。凡是使用static/private/final修饰的方法或者属性也属于该范畴,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)
双分派意味着请求的操作取决于请求的种类和接受者的类型