![](/img/trans.png)
[英]Spring Boot - Conditionally load module during runtime or compile-time
[英]left and right objects are evaluated / resolved during runtime or compile-time?
參考書籍練習......
有以下代碼..
Left left = createLeftInstance ();
Right right = createRightInstance ();
...並且考慮到上述兩種方法都可以返回Left和Right的所有子類的實例,在Java中調用以下方法......
left.invoke (right);
怎么解決:
實際上,我認為技術上正確的答案是“以上都不是”。
在編譯時,您需要知道left
變量( Left
)和right
變量( Right
)的聲明類型。 這將確定Left::invoke
方法的哪個方法重載1最適用於Right
類型的參數。
在運行時, left
的實際類型將決定調用哪個實際方法。
所以完整的答案是:
E)基於編譯時AND運行時類型的
left
和right
編譯時類型。
但是,我懷疑教科書中這個問題的關鍵是幫助您區分非重載方法的編譯時解析和運行時方法調度。 為此目的,A)“足夠正確”。
1 - 為了進行確定,編譯器需要將Right
及其超類型與Left
及其超類型聲明的invoke
方法的不同方法重載進行比較。 如果存在多個重載,則編譯器需要選擇“最具體的適用”重載。
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。 編譯時間類型的right
只是聲明right
的類型,即A.運行時類型的right
是參數的實際類型,即A2(參見輸出,它with argument A2
表示)。
Java有A ,它叫做單調度 :
right
與編譯時類型left
提供的方法相匹配) left
的運行時類型上 - 因為方法不會消失, left
肯定有一個具有相同簽名的方法,該方法在編譯時被選中。 此行為計為“調度”,因為它僅取決於left
(在運行時),它是“單一”。 使用內置println(Object)
和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);
)在編譯時結果中作為Object
傳遞在調用println(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
因為println
是使用參數的運行時類型手動選取的。 因此,如果有人真的需要它在Java中,它可以做,但它不會自動發生。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.