4 回答

TA貢獻1770條經驗 獲得超3個贊
您詢問的方法是main(),如下所示(我將類和方法編輯到最低限度)。正如您所發現的,它有效。
class Box<T> {
public static void main(String[] args) {
// do something
}
}
該方法很好,因為它與泛型類型沒有關聯T。這里,main是一個靜態方法,這意味著它在沒有對象實例的情況下被調用。
泛型不適用于靜態方法(或字段),但上面的示例并沒有這樣做。這是一個不同的示例,嘗試定義一個也使用的靜態方法T(但它不起作用):
class Box<T> {
public static void bar(T args) {
// do something
}
}
這個例子是一個靜態方法,將在沒有對象實例的情況下被調用 - 就像這樣:Box.bar(someArgs)- 但這是無效的。如果不首先創建某個泛型類型的實例Box,編譯器如何知道它T是什么?
可以定義一個靜態方法來使用泛型類型,但該方法完全獨立于T您的示例。對于某些單獨的泛型類型,有一種方法可以做到這一點X:
class Box<T> {
public static <X> void foo(X input) {
// do something
}
}
你可以這樣稱呼它:Box.foo("");

TA貢獻1828條經驗 獲得超6個贊
您不是“在這里執行課程”。main()
相反,您正在類中執行靜態方法。允許您這樣做的原因是類型擦除。泛型類型僅在編譯代碼時強制執行。在不聲明任何引用或創建Box<T>
編譯器實例的情況下,沒有理由檢查泛型類型。當您運行程序時,由于類型擦除,解釋器對通用代碼一無所知,因此它愉快地運行程序。

TA貢獻1946條經驗 獲得超4個贊
Java 與 C 不同。不存在“對于每一個可以想象到的 T/代碼庫中實際使用的每一個 T 都有一個 Box 類的變體”。只有盒子。例如:
new Box<String>().getClass() == new Box<Integer>().getClass() // this is true
您不會加載單獨的類等。
這確實有一些副作用: 不可能從String
變量 x 中導出: Box<?> x = new Box<String>();
- 該信息現在已經消失了。這稱為擦除。
實際上,泛型幾乎完全是編譯器想象的產物。這就像在打字稿中輸入信息等:它在編譯時就存在,編譯器將使用它來告訴您類型未對齊(編譯器錯誤),但是一旦編譯器接受所有信息,它就會被編譯為一種在運行時完全消除此信息的形式*。
這就是為什么上面的代碼可以毫無抱怨地工作:你有一個靜態方法,<T>
這里甚至不存在。
讓我們放大一下 get 和 set 方法以及 't' 字段: 它們完全是這樣的:private Object t; public void set(Object o) { this.t = t; } public Object get() { return t; }
只有一個例外:如果在編譯時,它沒有意義,編譯器將拒絕編譯它。此外,對于呼叫的任何呼叫者get
,都會默默地包含一個演員表。
*)不完全是;簽名中泛型的任何使用,因此,字段的類型、類自己的定義、和implements
行extends
以及方法的返回類型或參數類型中,都不會被消除,但它就像是對VM:VM不關心這些東西;它存在的唯一目的是,如果您調用javac
類路徑上的某些內容,javac 在與這些成員交互時知道泛型是什么。就這些。

TA貢獻1831條經驗 獲得超10個贊
Java 內部的泛型旨在為您的對象提供編譯時類型安全性。對于您的情況,它根本不訪問類中方法t內部的變量。main()這樣java就會愉快地編譯并運行程序了。
如果您Box在main()方法內實例化該類:
Box b = new Box(); // this is will produce "unsafe operations" note
b.set("this is the string");
System.out.println(b.get().getClass().getName());
根據最后一個變量賦值,您將在此處獲得一個字符串。
添加回答
舉報