簡體   English   中英

Java中的泛型子類型化問題

[英]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 CageAnimalCageAnimal ,這將在運行時因ClassCastException而失敗,因為ArrayList不是CageAnimal的子類型。

這條線

 public <T> void addAnimal(T t){

應該是

 public void addAnimal(T t){

因為CageAnimalCage是非常不同的東西。 看看您如何為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類進行參數化。 TCage<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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM