根據此https://docs.oracle.com/javase/specs/jls/se18/html/jls-15.html#jls-15.12.2.5,Java編譯器將嘗試選擇最具體的方法來呼叫多個適用和可訪問的可用。直覺是更具體的方法可以用不太具體的方法代替,但反之則不行。
所以我有點驚訝,當我們將模棱兩可的呼叫包裝在通用包裝器中時,這將不起作用,如下所示:
public class Test{
static <T> void direct(T t) { System.out.println("generic");}
static void direct(int t) { System.out.println("specific-int");}
static <T> void indirect(T t) { direct(t);}
public static void main ( String [] args ) {
direct(1); // print specific-int
indirect(1); // print generic
}
}
所以我們可以看到,只要呼叫direct就可以按預期作業。但是在呼叫 時indirect,會呼叫不太具體的方法。
如果我更改直接方法的型別,行為會發生變化
static void direct(short t) { System.out.println("specific-short");}
在這種情況下,兩行都列印出來generic(short在任何一種情況下都不會呼叫該方法),這告訴我在第一個實體中該文字1被隱式轉換為。如果是這樣,為什么不使用作為引數int的更具體的方法來呼叫它?int
uj5u.com熱心網友回復:
2個不相關的原因,兩者都導致通用版本:
拳擊
型別引數必然是 Object 的子型別(目前,Project Valhalla 是管道中的 Java 更新,可能會對此有所改變)。
因此,direct(t)您的方法中的呼叫indirect不可能被direct(int)視為最具體的版本,因為tin 的引數indirect不可能是int.
具體來說,當您呼叫1 時indirect(1),該 1int不是有效值indirect(因為indirect' 的引數是型別T; T 是具有 as 下界的型別引數java.lang.Object,并且1不是 的有效值Object)。
但是,java也有“裝箱”的概念,其中原語將自動轉換為其裝箱型別,但前提是代碼不會以其他方式編譯。你可以看到這個javap- 你會注意到編譯器替換1為Integer.valueOf(1)使其作業。
名稱是編譯時的
選擇哪種方法在編譯時被鎖定。請注意,覆寫(子型別實作完全相同的方法,即如果該方法用 注釋@Override,編譯器將接受它)完全是運行時的事情,java 總是從子型別中選擇實作,但static不會“做”子型別化,所以這里不相關。
您擁有的兩種direct方法不一樣;在 JVM 級別,它們具有完全不同的名稱,所以這只是2direct種方法中的哪一種被 選擇javac,因此,編譯時間是這里唯一重要的時間。
讓我明確一點:這兩種direct方法沒有相同的名稱,因此在運行時 JVM沒有根據型別選擇其中一種的自由。出于同樣的原因,它不能用呼叫來替換foo()呼叫bar()- not the same name。
indirect, 該方法不知道 T 是什么。所以就算不是拳擊的東西,也不可能叫!direct(int)- 查找兩種direct方法中的哪一種選擇不是在運行時完成的。
重申
鑒于:
public class Parent {
void foo(int i) { System.out.println("Parent-int"); }
void foo(Integer i) { System.out.println("Parent-Integer"); }
}
class Child extends Parent {
void foo(int i) { System.out.println("Child-int"); }
}
...
Parent p = new Child();
p.foo(5); // prints Child-int
p.foo(Integer.valueOf(5)); // prints Parent-Integer
最后的說明
你在評論中寫道:
“這告訴我文字 1 在第一個實體中被隱式轉換為 int”
No. integer literals in java are int - the java lang spec defines them as such. You can write short x = 5; only because of a special exemption rule that states you don't need the cast there, but languagewise, all non-decimal-pointed (and non 0x0p form) numeric AST nodes are treated as int. They are THEN implicitly casted if e.g. a long is needed.
You can ask javac to treat things as long by sticking a capital L at the end. Given:
void foo(byte i) {System.out.println("byte");
void foo(short i) {System.out.println("short");
void foo(int i) {System.out.println("int");
void foo(long i) {System.out.println("long");
foo(5); // prints 'int'
foo(5L); // prints 'long'
Even though '5' fits in 'byte', it is an int, and hence the int variant is chosen.
uj5u.com熱心網友回復:
why wasn't it called with the more specific method that takes in int as an argument?
The Java compiler decides which method to invoke at compile time. That is, for the indirect method, it chooses an overload of direct which can be safely invoked for all invocations of indirect.
The only such overload is the direct(T) method: this accepts any Object parameter, as does indirect(T). It can't invoke direct(int) because not all Objects are Integers.
indirect doesn't do anything different when invoked with an int parameter.
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/456092.html
上一篇:開放世界假設有什么好處?
