起因:使用EventBus庫時护姆,只是在父類中注冊了監(jiān)聽事件,把this傳遞過去了:EventBus.getDefault().register(this)溺忧,子類中并沒有注冊監(jiān)聽事件憋飞,但在響應(yīng)時調(diào)用的卻是子類中的響應(yīng)方法,EventBus是用反射來獲取注冊監(jiān)聽器的類的方法表然后調(diào)用相關(guān)方法的循狰,因此寫了個繼承與反射的例子來分析一下。
/* A.java */
public class A {
public void foo() {
}
}
/* B.java */
public class B extends A {
public void foo() {
}
public void foo2() {
}
public void foo3() {
}
}
public class Program {
public static void main(String[] args) {
A obj = new B();
Class<?> clazz = obj.getClass();
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
}
}
輸出:
foo
foo3
foo2
wait
wait
wait
equals
toString
hashCode
getClass
notify
notifyAll
這里得到的方法列表是B類中的方法券勺。
解釋:
因為 A obj = new B() , obj的實際類型是B绪钥,obj調(diào)用getClass()方法時,由于鏈接時的動態(tài)綁定关炼,obj.getClass()方法被重新定向到了類B#getClass()方法的方法調(diào)用入口程腹,所以obj.getClass()實際執(zhí)行的是B#getClass()函數(shù),因此得到的是B的Class實例儒拂。
因此 clazz.getMethods() 得到的自然是類B的方法表了寸潦。
關(guān)于"this":
在類A中添加方法:
public void fuck() {
System.out.println(this);
System.out.println(this.getClass().getName());
}
在main()方法中調(diào)用fuck():
A obj = new B();
obj.fuck();
輸出:
test.demo.B@15db9742
test.demo.B
在A類中的this被重新定向到了B類的實例。
解釋:
類B繼承類A社痛,同對getClass()函數(shù)的分析一樣见转,類B在編譯時自動拷貝了類A中的所有方法,類B沒有顯示地重寫fuck()函數(shù)蒜哀,因此在類B內(nèi)也有一份與類A中fuck()函數(shù)相同的fuck()函數(shù)的拷貝斩箫。在執(zhí)行obj.fuck()時,由于鏈接時的動態(tài)綁定obj.fuck()方法被重新定向到了類B#fuck()方法的方法調(diào)用入口撵儿,所以obj.fuck()乘客,實際執(zhí)行的是B#fuck()函數(shù),因此A.java文件中fuck()函數(shù)的this是B的實例也就不足為奇了统倒,因為obj.fuck()方法不是調(diào)用類A而是調(diào)用類B中的fuck()寨典。