简体   繁体   English

使用Java Generics扩展

[英]using extends with Java Generics

Lets say that I have the following code: 可以说我有以下代码:

public class Shelter<A extends Animal, B extends Animal>
{
     List<A> topFloor = new Vector<A>();
     List<B> bottomFloor = new Vector<B>();

     public A getFirstTopFloorAnimal(){return topFloor.get(0);}
     public B getFirstBottomFloorAnimal(){return bottomFloor.get(0);}

     //These 3 methods compile but when I try to use it, they all only return objects
     public List<Animal> getAnimals()
     { 
         List<Animal> a = new Vector<Animal>(topFloor); 
         a.addAll(bottomFloor); 
         return a;
     }

     public List<A> getTopFloor(){return topFloor;}
     public List<B> getBottomFloor(){return bottomFloor;}
}

I then try to do something like the following: 然后,我尝试执行以下操作:

for(Animal a : shelter.getTopFloor()){
    a.growl();
}

But I compiler error that I get the error that A is an object, not an animal. 但是我遇到了一个编译器错误,我得到的错误是A是一个对象,而不是动物。 The same happens if I try to use the other methods. 如果我尝试使用其他方法,也会发生相同的情况。 Any ideas why this is? 任何想法为什么会这样? Does this have to do with the List<String> is NOT a List<Object> idea in the Generics tutorial? 这与泛型教程中的List<String>不是List<Object>想法有关吗?

Thank you 谢谢

Generics are only a compile-time concept in order to increase type-safety. 泛型只是为了提高类型安全性的编译时概念。

You can't use them to filter the values added to a collection at run-time. 您不能在运行时使用它们来过滤添加到集合中的值。 You have to do the filtering manually (using instanceOf , for example) 您必须手动进行过滤( instanceOf ,使用instanceOf

For example this would work and will let you add a Date : 例如,这将起作用,并允许您添加一个Date

List<String> list = new ArrayList<String>();
((List) list).add(new Date());

So the solution to your (yet-unseen by us) problem is not to use the raw type when adding elements. 因此,解决您的问题(我们尚未发现)的解决方案是在添加元素时不使用原始类型。

My best guess is that you've declared shelter to use a raw type as follows: 我最好的猜测是,您已经声明使用以下原始类型来shelter

Shelter shelter = new Shelter();

You really should do the following: 您确实应该执行以下操作:

Shelter<Cat,Dog> shelter = new Shelter<Cat,Dog>();

Then you'd actually use the generics features. 然后,您实际上将使用泛型功能。

See also 也可以看看

  • Effective Java 2nd Edition : Item 23: Don't use raw types in new code . 有效的Java 2nd Edition项目23:不要在新代码中使用原始类型

    If you use raw types, you lose all the safety and expressiveness benefits of generics. 如果使用原始类型,则将失去泛型的所有安全性和表达优势。

  • JLS 4.8 Raw Types JLS 4.8原始类型

    The use of raw types is allowed only as a concession to compatibility of legacy code. 原始类型的使用仅允许作为遗留代码兼容性的让步。 The use of raw types in code written after the introduction of genericity into the Java programming language is strongly discouraged. 强烈建议不要在将通用性引入Java编程语言之后在编写的代码中使用原始类型。 It is possible that future versions of the Java programming language will disallow the use of raw types. 未来版本的Java编程语言可能会禁止使用原始类型。


List<String> is NOT a List<Object> List<String>不是List<Object>

Yes, Java generics are are neither covariant nor contravariant . 是的,Java泛型既不是协变也不协变 That is only an issue if you're trying to cast one generic type to another, which doesn't seem to be what you're trying to do. 如果您试图将一种泛型类型转换为另一种泛型类型,那只是一个问题,这似乎并不是您要尝试做的。

Also, unlike what your subject title says, I don't think this has anything to do with extends to bound the type parameters in generics. 另外,与您的主题标题所说的不同,我认为这与extends以绑定泛型中的类型参数没有任何关系。

I think the core of your problem is here: 我认为您问题的核心在这里:

for(Animal a : shelter.getTopFloor()){
    a.growl();
}

How is shelter defined? 如何定义shelter所?

It's because when you put the items in the Vector , they go in as objects, not instances of Animal . 这是因为当您将项目放入Vector ,它们作为对象进入,而不是Animal实例。

 public List<Animal> getAnimals()
 { 
     Vector a = new Vector(topFloor); // <-- Not generic!
     a.addAll(bottomFloor); 
     return a;                        // <-- Returning non-generic Vector.
 }

Try this instead: 试试这个:

 Vector<Animal> a = ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM