[英]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.