泛型的兼容性
因?yàn)榉盒褪窃贘ava SE5的時(shí)候引入的测垛,而為了兼容之前沒(méi)有泛型的代碼坟奥,而擦除是最好的兼容方法蜈抓。
擦除的主要問(wèn)題是將非泛化代碼從泛化代碼的的轉(zhuǎn)變過(guò)程,繼續(xù)使用跋破,直至客戶端準(zhǔn)備好用泛型重寫這些代碼簸淀。這個(gè)動(dòng)機(jī)不會(huì)破壞現(xiàn)有的代碼。
擦除的代價(jià)也是顯著的幔烛,泛型不能顯示地引用運(yùn)行時(shí)類型的操作之中啃擦,例如轉(zhuǎn)型,instanceof
和new
表達(dá)式饿悬,這是因?yàn)樗嘘P(guān)于參數(shù)的類型信息都丟失了令蛉。
所以無(wú)論何時(shí),當(dāng)在編寫泛型代碼的時(shí)候狡恬,必須時(shí)刻提醒自己珠叔,只是看起來(lái)具有有關(guān)參數(shù)的類型信息而已。
如果編寫了以下的代碼段弟劲。
class Foo<T> {
T var;
}
那么祷安,看起來(lái)當(dāng)在創(chuàng)建Foo
的實(shí)例時(shí)。
Foo<Cat> f = new Foo<Cat>();
class Foo
中的代碼應(yīng)該知道現(xiàn)在工作于Cat
之上兔乞,盡管如此汇鞭,在編寫代碼的時(shí)候凉唐,就必須強(qiáng)烈地知道var
只是一個(gè)Object
類型。
擦除和遷移兼容性表明霍骄,使用泛型不是強(qiáng)制的台囱。
class GenericBase<T> {
private T element;
public T getElement() {
return element;
}
public void setElement(T element) {
this.element = element;
}
}
class Derived1<T> extends GenericBase<T> {
}
class Derived2 extends GenericBase {
}
//class Derived3 extends GenericBase<?> {
// Strange error
//}
public class ErasureAndInheritance {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
Derived2 d2 = new Derived2();
Object obj = d2.getElement();
d2.setElement(obj);// warning here
}
}
上面的代碼中,Derived2
繼承了GenericBase
读整,但是沒(méi)有任何泛型參數(shù)簿训,但是編譯器沒(méi)有發(fā)出警告。而警告在set()
被調(diào)用的時(shí)候才出現(xiàn)米间。
為了關(guān)閉警告强品,Java提供了一個(gè)注解(在Java SE5版本前不被支持)
@SuppressWarnings("unchecked")
需要注意的是,這個(gè)注解應(yīng)該盡可能地被放置在可以產(chǎn)生這類警告的方法之上屈糊,而不是整個(gè)類上的榛。當(dāng)要關(guān)閉警告的時(shí)候,最好盡量地"聚焦逻锐,這樣就不會(huì)過(guò)于寬泛地關(guān)閉警告困曙,而導(dǎo)致意外地屏蔽掉真正的問(wèn)題。
而Derived3
的錯(cuò)誤意味著編譯器期待得到的是一個(gè)原生基類谦去,而不是一個(gè)不確定類型的類。
當(dāng)希望將類型參數(shù)不僅僅當(dāng)做Object
處理的時(shí)候蹦哼,就需要付出額外的努力去管理邊界鳄哭,并且與C++等語(yǔ)言獲得參數(shù)化類型相比,需要付出多得多的努力來(lái)獲得少得回報(bào)纲熏。這并不是說(shuō)這些語(yǔ)言比Java更得心應(yīng)手妆丘,而是說(shuō)它們的參數(shù)類型化機(jī)制比Java更加強(qiáng)大、更靈活局劲。