[英]How does a method with a varargs of Bounded Wildcard type compile?
我對這個示例的工作方式摸不着頭腦,而且似乎可以正確打印。
public class Test {
static class Shape {
public String toString() {
return "Shape";
}
}
static class Circle extends Shape {
public String toString() {
return "Circle";
}
}
static class Square extends Shape {
public String toString() {
return "Square";
}
}
public static void wildCardVarArgs(ThreadLocal<? extends Shape>... list) {
for (ThreadLocal<? extends Shape> s : list) {
System.out.println(s.get().toString());
}
}
public static void test() {
ThreadLocal<Shape> shape = new ThreadLocal<>();
shape.set(new Shape());
ThreadLocal<Square> square = new ThreadLocal<>();
square.set(new Square());
ThreadLocal<Circle> circle = new ThreadLocal<>();
circle.set(new Circle());
wildCardVarArgs(shape, square, circle);
}
}
呼叫測試將打印:
"Shape"
"Square"
"Circle"
直觀上講,這是有道理的,因為方法簽名被描述為接受任意數量的參數,只要它們的類型為ThreadLocal且具有Shape的任何擴展名即可。 因此,將ThreadLocal<Square>
與ThreadLocal<Circle>
一起傳遞就可以了。
但是,如何以運行時可以確定適當的字符串重載的方式進行編譯? 我對泛型類型擦除的朦朧理解使這種方法簽名似乎甚至無法編譯。 我本以為wildCardVarArgs的簽名在字節碼中變成了wildCardVarArgs(ThreadLocal[])
樣子,似乎執行應該遇到ClassCastException。 但是我想得越多,我就越困惑。
任何人都可以理解這一點,並且編譯對ThreadLocal的Bounded Wildcard類型有什么作用?
基本上,即使刪除類型,也可以得到以下信息:
....
public static void wildCardVarArgs(ThreadLocal... list) {
for (ThreadLocal s : list) {
Object o = s.get(); //Compiler knows there's "at least" Object inside
System.out.println(o.toString()); //And all Objects have "toString"
}
}
....
因此,無論您輸入什么內容,所有對象的基類(即Object)都具有toString方法,在您的情況下,該方法將被覆蓋。 因此,在對象類型變量上調用它永遠不會失敗,並且在您的情況下-調用重寫方法。
添加:
現在,如果您將一些新方法添加到Shape類中,將發生以下情況:
public static void wildCardVarArgs(ThreadLocal<? extends Shape>... list) {
for (ThreadLocal<? extends Shape> s : list) {
Shape o = s.get(); //Compiler knows there's "at least" Shape inside
System.out.println(o.someCustomMethod()); //And all Shapes have "someCustomMethod", does not matter if it is overriden or not
}
}
有了這些代碼,編譯器就可以肯定地知道,無論您將此方法提供給哪種ThreadLocal,它都包含某種 Shape實現。 它實際上並不關心它是哪一個,但是,它可以保證除了某種Shape之外 ,您什么都不給。 因此,它可以在編譯時檢查Shape是否確實具有一些someCustomMethod
。 再一次,它並不在乎此時是否有人重寫它,它只是調用它。 如果被覆蓋-被覆蓋的被調用。 如果未覆蓋-則調用Shape類中的原始對象。
更多添加:
我本以為wildCardVarArgs的簽名在字節碼中變成了wildCardVarArgs(ThreadLocal [])的樣子,似乎執行應該遇到ClassCastException。
這就是發生的情況(不是數組部分,而是擦除)。 也就是說,編譯后剩下的基本上是:
public static void wildCardVarArgs(ThreadLocal... list) {
for (ThreadLocal s : list) {
Object o = s.get();
Shape p = (Shape)o; //Java hopes this won't fail, because compiler checked that it should not
System.out.println(p.someCustomMethod());
}
}
但是,Java並不在乎。 它希望在編譯時能正確發現所有錯誤,因此不應在運行時發生此類錯誤(破壞者:如果有人不小心,它們確實會不時發生)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.