繁体   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