简体   繁体   中英

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. 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?

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)

For example this would work and will let you add a 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 = 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 .

    If you use raw types, you lose all the safety and expressiveness benefits of generics.

  • JLS 4.8 Raw Types

    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. It is possible that future versions of the Java programming language will disallow the use of raw types.


List<String> is NOT a List<Object>

Yes, Java generics are are neither covariant nor contravariant . 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.

I think the core of your problem is here:

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

How is shelter defined?

It's because when you put the items in the Vector , they go in as objects, not instances of 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 = ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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