3 回答

TA貢獻1815條經驗 獲得超6個贊
實際上,我認為技術上正確的答案是“以上都不是”。
在編譯時,你需要知道
left
變量(Left
)和right
變量(Right
)的聲明類型。這將決定該方法的哪個方法重載1Left::invoke
最適用于 type 的參數Right
。在運行時, 的實際類型
left
將決定調用哪個實際方法。
所以完整的答案是:
E) 基于 的編譯時和運行時類型
left
以及 的編譯時類型right
。
但是,我懷疑教科書上這個問題的重點是幫助你區分非重載方法的編譯時解析和運行時方法調度。為此,A) 是“足夠正確”的。
1 - 為了做出決定,編譯器需要將其超類型與聲明Right
的方法及其超類型的不同方法重載進行比較。如果有多個重載,編譯器需要選擇“最具體適用”的重載。invoke
Left

TA貢獻1744條經驗 獲得超4個贊
A) 是這里的正確答案。
下面的代碼演示了這一點。
public class Main001 {
public static void main(String[] args) {
A right = createRightInstance();
B left = createLeftInstance();
left.invoke(right);
System.out.println("Done!!!");
}
public static B createLeftInstance() {
return new B2();
}
public static A createRightInstance() {
return new A2();
}
}
class A{
}
class A1 extends A{
}
class A2 extends A1{
}
class B{
public void invoke(A x) {
System.out.println("Invoking method A on B with argument " + x.getClass().getName());
}
public void invoke(A1 x) {
System.out.println("Invoking method A1 on B with argument " + x.getClass().getName());
}
public void invoke(A2 x) {
System.out.println("Invoking method A2 on B with argument " + x.getClass().getName());
}
}
class B1 extends B{
public void invoke(A x) {
System.out.println("Invoking method A on B1 with argument " + x.getClass().getName());
}
public void invoke(A1 x) {
System.out.println("Invoking method A1 on B1 with argument " + x.getClass().getName());
}
public void invoke(A2 x) {
System.out.println("Invoking method A2 on B1 with argument " + x.getClass().getName());
}
}
class B2 extends B1{
public void invoke(A x) {
System.out.println("Invoking method A on B2 with argument " + x.getClass().getName());
}
public void invoke(A1 x) {
System.out.println("Invoking method A1 on B2 with argument " + x.getClass().getName());
}
public void invoke(A2 x) {
System.out.println("Invoking method A2 on B2 with argument " + x.getClass().getName());
}
}
這個例子打印
Invoking method A on B2 with argument A2
Done!!!
這意味著 A) 是正確答案。
為什么是這個意思?
嗯......因為:
1)調用了 B2 類的方法(如輸出所示)并且 B2 是運行時類型left(編譯時類型left是 B)。
2) 調用了一個帶參數 A 的方法(注意 A 是 的編譯時類型right),即使 的運行時類型right是 A2。編譯時類型 ofright只是right聲明的類型,即 A。運行時類型 ofright是參數的實際類型,即 A2(請參閱輸出,它with argument A2在那里說明)。

TA貢獻2065條經驗 獲得超14個贊
Java 有A,它被稱為single dispatch:
方法重載由編譯器在編譯時選擇(將 的編譯時類型與 的編譯時類型
right
提供的方法相匹配left
)方法調用發生在運行時類型上
left
——因為方法不會消失,left
當然有一個方法具有在編譯時選擇的相同簽名。此行為算作“調度”,并且因為它僅取決于left
(在運行時),所以它是“單一的”。
使用內置println(Object)
and的超級簡單演示println(char[])
:
char c[]={'a','b','c'};
System.out.println(c);
Object o=c;
System.out.println(o);
它會產生類似的結果
abc
[C@1540e19d
第一行顯示連接字符數組,第二行顯示在編譯時傳遞println(char[])的完全相同的數組(可以添加一些檢查,如)導致調用重載,而不管運行時類型如何。println(o==c);Objectprintln(Object)
B和C可能不存在。
D稱為多重分派,當方法簽名也在運行時使用參數的實際運行時類型選擇時,并且所選方法在 的運行時類型上被調用left。java默認是不支持的,可以用反射來實現,下面是一個單參數的例子:
public static void trickyprintln(Object o) throws Exception {
System.out.getClass().getMethod("println",o.getClass()).invoke(System.out,o);
}
public static void main (String[] args) throws Exception {
char c[]={'a','b','c'};
trickyprintln(c);
Object o=c;
trickyprintln(o);
}
這一個導致
abc
abc
asprintln是手動選擇的,使用參數的運行時類型。所以如果有人真的需要它,在 Java 中是可以做到的,但它不會自動發生。
添加回答
舉報