[英]Java use generics to set the primitive type of an array later
我試圖用Java編寫一些簡單的數字代碼,以便以后可以在float和double之間進行選擇。 我的課程的簡化版本類似於以下示例:
public class UniformGrid<T> {
public T[] data;
public UniformGrid(int arrayDim) {
data = new T[arrayDim];
}
}
這不起作用,嘗試編譯時出現generic array creation
錯誤。 谷歌搜索和閱讀一些我了解了java.lang.reflect.Array
SO答案,並嘗試使用
data = (T[]) Array.newInstance(T.class, arrayDim);
由於T是(可能)是原始類型,因此這也不起作用。 我的Java知識非常生銹(尤其是在泛型時),我想知道為什么新運算符不能與泛型數組類型一起使用。 當然,我也很感興趣如何用Java解決這一問題。
由於類型Erase,您無法在Java中創建通用數組。 解決此問題的最簡單方法是使用List<T>
。 但是,如果必須使用數組,則可以對數組使用Object[]
並確保僅將T
對象放入其中。 (這是ArrayList
采取的策略。)
例如:
private Object[] data = new Object[10];
private int size = 0;
public void add(T obj) {
data[size++] = obj;
}
public T get(int i){
return (T) data[i];
}
當然,您會從編譯器中收到未經檢查的警告,但是您可以取消該警告。
創建數組時無法使用泛型,因為您在運行時不知道T是什么類型。 這稱為類型擦除 。
解決方案很簡單:使用List<T> data
。
抱歉,您必須采取另一種方法:
如果您真的需要它,我會研究代碼生成,也許是作為自動構建的一部分。 (對源代碼的簡單搜索和替換應該能夠將在double上運行的庫轉換為在float上運行的庫。)
只要使用Float
和Double
而不是float
和double
,這都是可能的,因為Java泛型中不允許使用基本類型。 當然,這可能會很慢。 而且,您將無法(安全地)允許直接公共訪問陣列。 因此,該答案不是很有用,但在理論上可能很有趣。 無論如何,如何構造數組...
data = (T[]) new Object[arrayDim];
這會給您一個警告,但這並不是直接擔心的事情。 它以這種特殊形式工作-在通用構造函數內部, data
是對此新構造對象的唯一引用。 請參閱此頁面。
您將無法以自己喜歡的方式公開訪問此數組對象。 您需要在UniformGrid<T>
設置方法來獲取和設置對象。 這樣,編譯器將確保類型安全,並且運行時不會給您帶來任何問題。
private T[] data;
public void set(int pos, T t) {
data[pos] = t;
}
public T get(int pos) {
return data[pos];
}
在這種情況下,要set
的接口將(在編譯時)強制傳遞正確的類型。 底層數組的類型為Object[]
但這沒關系,因為它可以采用任何引用類型-並且所有泛型類型實際上都是List<Object>
或類似的東西,無論如何在運行時。
有趣的是吸氣劑。 編譯器“知道” data
類型為T[]
,因此,吸氣劑將進行干凈編譯,並承諾返回T
因此,只要您將data
保密,並且僅通過get
和set
進行訪問,一切都會很好。
一些示例代碼在ideone上 。
public static void main(String[] args) {
UniformGrid<A> uf = new UniformGrid<A>(1);
//uf.insert(0, new Object()); // compile error
uf.insert(0, new A());
uf.insert(0, new B());
Object o1= uf.get(0);
A o2= uf.get(0);
// B o2= uf.get(0); // compiler error
System.out.println(o1);
System.out.println(o2);
System.out.println("OK so far");
// A via_array1 = uf.data[0]; // Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [LA;
}
如您所願,存在uf.insert(0, new Object())
和B o2= uf.get(0);
編譯錯誤B o2= uf.get(0);
但是您不應該將data
成員公開。 如果這樣做,則可以編寫和編譯A via_array1 = uf.data[0];
。 該行看起來應該沒問題,但是您遇到了運行時異常: Ljava.lang.Object; cannot be cast to [LA;
Ljava.lang.Object; cannot be cast to [LA;
。
簡而言之, get
和set
接口提供了一個安全的接口。 但是,如果您在使用數組時遇到了很多麻煩,則應該只使用ArrayList<T>
。 故事的寓意:任何語言(Java或C ++),具有泛型或不具有泛型, 只需對array拒絕即可 。 :-)
有效Java,第二版中的項目25討論了此問題:
數組是協變的且是精確化的; 泛型是不變的且已刪除。 因此,對於泛型,數組提供運行時類型安全性,但不提供編譯時類型安全性,反之亦然。 一般來說,數組和泛型不能很好地混合使用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.