簡體   English   中英

具有綁定通配符類型的可變參數的方法如何編譯?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM