java動態/靜態繫結以及雙分派
阿新 • • 發佈:2019-02-16
動態繫結:程式在執行期間而不是在編譯期間,根據所引用物件的實際型別呼叫對應的方法,重寫以及介面的實現都屬於該範疇,使用實際的物件資訊來完成API的呼叫
outputpublic 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"); } }
Father.method
Son.method
Daughter.method
儘管引用的型別都是Father,但是在執行時卻呼叫的是實際型別的方法,也就是說父類引用指向子類例項時,會根據實際例項型別呼叫對應的方法
靜態繫結:在編譯期間已經確定執行的方法,API的過載屬於該範疇,也就是說需要執行的方法在編譯期間已經確定。凡是使用static/private/final修飾的方法或者屬性也屬於該範疇,static修飾的方法或者屬性屬於類,不能被繼承也就是說無法重寫。private只有該類的物件能夠訪問,不能被繼承也就是說無法重寫,final修改的屬性不允許重新複製,可以理解為常量,final 修飾的方法不允許被重寫。使用類資訊完成API的呼叫
outputpublic 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"); } }
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)
雙分派意味著請求的操作取決於請求的種類和接受者的型別