我玩弄泛型和發現,讓我驚訝的是,下面的代碼編譯:爲什麼在推斷數組類型時java類型不安全?
class A {}
class B extends A {}
class Generic<T> {
private T instance;
public Generic(T instance) {
this.instance = instance;
}
public T get(){ return instance; }
}
public class Main {
public static void main(String[] args) {
fArray(new B[1], new Generic<A>(new A())); // <-- No error here
}
public static <T> void fArray(T[] a, Generic<? extends T> b) {
a[0] = b.get();
}
}
我希望T
被推斷爲B
。 A
不延伸B
。那爲什麼編譯器不會抱怨呢?
T
似乎被推斷爲Object
,因爲我也可以通過Generic<Object>
。
此外,當實際運行的代碼,它將引發對a[0] = b.get();
線的ArrayStoreException
。
我沒有使用任何原始泛型類型。如果T
實際上被推斷爲B
,我覺得這個異常可以通過編譯時錯誤或者至少一個警告來避免。
當與List<...>
等效進一步的測試:
public static void main(String[] args) {
fList(new ArrayList<B>(), new Generic<A>(new A())); // <-- Error, as expected
}
public static <T> void fList(List<T> a, Generic<? extends T> b) {
a.add(b.get());
}
這不會產生與誤差:
The method fList(List<T>, Generic<? extends T>) in the type Main is not applicable for the arguments (ArrayList<B>, Generic<A>)
一樣更通用的情況下:
public static <T> void fList(List<? extends T> a, Generic<? extends T> b) {
a.add(b.get()); // <-- Error here
}
的編譯器正確地認識到第一個?
可能比第二個?
更靠後。
例如如果第一個?
是B
而第二個?
是A
那麼這是不安全的。
那麼,爲什麼第一個例子沒有產生類似的編譯器錯誤呢?這只是一個疏忽嗎?還是有技術限制?
我可能會產生一個錯誤的唯一方法是通過顯式地提供類型:從2005年
Main.<B>fArray(new B[1], new Generic<A>(new A())); // <-- Not applicable
我並沒有真正找到過我自己的研究任何東西,除了this article(仿製藥之前) ,其中談到陣列協方差的危險。
數組協變似乎暗示了一個解釋,但我想不出一個。
最新的JDK是1.8.0.0_91
我不知道你是否會碰到Java的類型刪除泛型?只是一個想法,我沒有時間看看更接近的ATM。 – Ukko