2

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

10
  • 3
    Any reason why you are using vectors? They are pretty much obsolete. Commented Apr 18, 2010 at 13:22
  • 1
    btw, what is the problem? Where do you call getAnimals and what do you expect to have there? Commented Apr 18, 2010 at 13:24
  • What do you mean when you say "when I try to use getAnimals I get a [list] of objects instead of Animal"? Commented Apr 18, 2010 at 13:25
  • I edited the question to show the actual problem. I probably should have done that from the start :) Commented Apr 18, 2010 at 13:29
  • 1
    Looks fine so far. Can you provide an example of how you're adding animals to the shelter? Commented Apr 18, 2010 at 13:31

4 Answers 4

4

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.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for the quick response but, why wouldn't it be known at compile that List<Digraph> + List<DiGraph> = List<DiGraph>?
how does this question relate to your original one?
Because isn't that what I'm doing in getAnimals()?
And it compiles - so the generics part work fine. What do you expect to happen?
Arg, I found the problem within my own code. Thanks for the help!
2

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.

Comments

1

I think the core of your problem is here:

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

How is shelter defined?

1 Comment

+1 I didn't see that it was a compile error with the loop. It looks like it might be something like Shelter shelter = new Shelter();
0

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

2 Comments

oops, sorry. That is what I had. I edited the question to fix that. Thanks for the catch.
Should really be List<Animal> animals = new ArrayList<Animal>();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.