[英]Generics Subtyping issue in java
我正在嘗試學習Java的子類型化,而我在泛型方面並不是一個更好的人,所以我遇到了這個問題或疑問-
import java.util.ArrayList;
import java.util.Collection;
interface Animal<T>{}
class Lion implements Animal<Lion>{}
class Butterfly implements Animal<Butterfly>{}
class Cage<T>{
public <T> void addAnimal(T t){
}
}
interface CageAnimal<E> extends Collection<E>{}
public class SubType<T> {
public <T> SubType() {
Lion lion = new Lion();
Butterfly butterfly = new Butterfly();
/**
* **Here inside Lion cage, we added Butterfly : WRONG**
*/
Cage<Lion> cageLion = new Cage<Lion>();
cageLion.addAnimal(lion);
cageLion.addAnimal(butterfly);
CageAnimal<Lion> cageAnimalLion = (CageAnimal<Lion>) new ArrayList<Lion>();
cageAnimalLion.add(lion);
//cageAnimalLion.add(butterfly);//Butterfly is Not Supposed to add here as it is the cage of Lion
}
}
在上面的示例中,當我聲明Cage時,為什么我可以添加Butterfly,而在我創建CageAnimal類型的相同情況下,我無法添加任何Buttefly
Cage<Lion> cageLion = new Cage<Lion>();
cageLion.addAnimal(lion);
cageLion.addAnimal(butterfly);
如果是籠子
Cage<Animal> cageAnimalLion = new Cage<Lion>();
cageAnimalLion.addAnimal(lion);
cageAnimalLion.addAnimal(butterfly); //Throwing Compile Error
像這樣聲明Cage
類:
class Cage<T extends Animal> {
public void addAnimal(T t) { ... }
}
如果您通過以下方式聲明addAnimal
方法...
public void <T> addAnimal(T t)
...您正在“隱藏” T
類型參數,且其名稱具有不同的類型參數。 就像您這樣聲明方法一樣:
class Cage<T extends Animal> {
public void <X> addAnimal(X t) { ... }
}
...這顯然沒有做好。 另一方面,在我編寫的第一個版本中,類的聲明中的T
in和方法都相同。
此外,聲明<T extends Animal>
綁定可確保籠子只能是擴展Animal
的類型,即Cage<Lion>
, Cage<Butterfly>
,但Cage<String>
是非法的。
當然,您不能將ArrayList
CageAnimal
為CageAnimal
,這將在運行時因ClassCastException
而失敗,因為ArrayList
不是CageAnimal
的子類型。
這條線
public <T> void addAnimal(T t){
應該是
public void addAnimal(T t){
因為CageAnimal
和Cage
是非常不同的東西。 看看您如何為Cage
定義通用參數:
public <T> void addAnimal(T t){
}
您在方法上放置的<T>
表示該方法具有自己的通用參數,與您在類中定義的參數不同。 如果將其從方法簽名中刪除,它將使用該類的通用參數。
例如
public void addAnimal(T t)
您的問題是,從根本上說,您的Cage
將接受任何T
,因此也接受任何Animal
。 各種T
並非都引用相同的T值,它們是類或方法局部的變量。
您可以編寫如下內容:
public class Cage<T> {
public void addAnimal(Animal<T> caged) {
}
}
現在,在以下常見情況下,至少會出現編譯器錯誤:
Cage<Lion> c=new Cage<Lion>();
c.add(new Butterfly()); // should error AFAIK
但是,在以下情況下,它將減少為警告:
Animal butterfly=new Butterfly();
Cage<Lion> c=new Cage<Lion>();
c.add(butterfly); // warning about raw types... IIRC
因為,從根本上說, Cage
仍然可以接受任何Animal
。
編輯:請注意,前面提到的刪除addAnimal
方法中的<T>
本地的addAnimal
將對此更好地工作。
通過聲明public <T> void addAnimal(T t)
,就可以對方法以及Cage
類進行參數化。 該T
與Cage<T>
的T
沒有關系。
您可以擁有:
class Cage<T extends Animal<T>> {
public void addAnimal(T animal) {
}
}
或者,如果您希望Animal
歸還,則:
class Cage<T extends Animal<T>> {
public T addAnimal(T animal) {
}
}
class Cage<T>{
public <T> void addAnimal(T t){
}
}
Cage類具有通用方法addAnimal。 與該方法關聯的通用類型會導致與該類關聯的通用類型被忽略,而參數的類型將用作該方法的通用類型。
嘗試執行以下示例以查看發生了什么:
public class TestCage {
/**
* @param args
*/
public static void main(String[] args) {
Cage<String> cage1 = new Cage<String>();
cage1.addAnimal(new String("test1"));
cage1.addAnimal(new Integer(1));
cage1.addAnimal2(new String("test2"));
//cage1.addAnimal2(new Integer(1)); //Uncomment to throw error
}
}
class Cage<T>{
public <T> void addAnimal(T t){
System.out.println("T: " + t.getClass().getName());
}
public void addAnimal2(T t){
System.out.println("T: " + t.getClass().getName());
}
}
總之,通過將通用方法添加到類中,將忽略該類的通用類型參數,並將傳遞給該方法的參數的類型用作該方法的通用類型參數。
嘗試將<T>
從public <T> void addAnimal(T t)
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.