views:

201

answers:

6

Hi all,

I'm sure this has been answered before, but I really cannot find it.

I have a java class SomeClass and an abstract class SomeSuperClass. SomeClass extends SomeSuperClass.

Another abstract method has a method that returns a Collection<SomeSuperClass>. In an implementation class, I have a Collection<SomeClass> myCollection

I understand that I cannot just return myCollection, because Collection<SomeClass> does not inherit from Collection<SomeSuperClass>. Nevertheless, I know that everything in myCollection is a SomeSuperClass because after all, they're SomeClass objects which extend SomeSuperClass.

How can I make this work?

I.e. I want

public class A
{
  private Collection<SomeClass> myCollection;

  public Collection<SomeSuperClass> getCollection()
  {
    return myCollection; //compile error!
  }
}

The only way I've found is casting via a non-generic type and getting unchecked warnings and whatnot. There must be a more elegant way, though? I feel that also using Collections.checkedSet() and friends are not needed, since it is statically certain that the returned collection only contains SomeClass objects (this would not be the case when downcasting instead of upcasting, but that's not what I'm doing). What am I missing?

Thanks!

+2  A: 

You can't do this. You have a Collection<SomeClass> and wish to return a Collection<SuperClass>

Now imagine that someone has your returned Collection - and they try to insert a different subclass of SuperClass, SomeOtherClass. This should be allowed on your SuperClass collection - but it can't because it's actually a Collection<SomeClass>, unbeknownst to anyone but the private member of A.

Steven Schlansker
Aha! Thanks :-)Sounds like I need an immutable view.
skrebbel
Hmm is there standard library support for immutable views? :-)
skrebbel
Why is 'my solution' possible? Am I missing something (see my Answer below)
Stefan Hendriks
-1 you can do this. See ishmeister's answer below using wildcards.
Adam
A: 

A collection of SubType is not substitutable for SuperType.

Everyone
Well, clearly I know that. My problem was that I wanted to work around that. My real problem was that I did not understand *why* a collection of SubType is not substitutable for SuperType. Answering a question that goes "I can't do X, is there a workaround" by "You can't do X" sounds like you're just trying to score stackoverflow points.
skrebbel
Missed the bit in the middle about a 'more elegant way'. I stand corrected ...
Everyone
You might want to take a gander at http://stackoverflow.com/questions/15496/hidden-features-of-java/55221#55221
Everyone
A: 

I am not sure why; perhaps someone else can explain this; but it works if you do:

public abstract class SomeSuperClass<E> {
    abstract public Collection<SomeSuperClass<E>> getCollection();
}

and:

public class Someclass extends SomeSuperClass {
    @Override
    public Collection<Someclass> getCollection() {
        // TODO Auto-generated method stub
        return null;
    }
}
Stefan Hendriks
I'd be very interested in that too. Sure you're not getting any unchecked warnings somehow? Either way, you're extending a generic class without making the subclass generic, that sounds like a weird thing to start with..
skrebbel
Yes it is strange. If you do make the subclass more concrete you get:public class Someclass extends SomeSuperClass<Someclass> { @Override public Collection<SomeSuperClass<Someclass>> getCollection() { // TODO Auto-generated method stub return null; }}I have never used such a construction before, it does not really look like a good way to me.
Stefan Hendriks
Your Someclass extends SomeSuperClass, which is a raw type because SomeSuperClass is declared as <E>. I believe that since you extend a raw type, you'll get a warning for that but then not get further unchecked warnings on the individual methods even though they are actually unchecked conversions.
Steven Schlansker
A: 

perhaps, you should do some workaround.

for example, you should make some "HolderClass" with generic extension, and then you'll be able to put weather your SomeClass, weather your SomeSuperClass.

take a look:

public class HolderClass<E extends SomeSuperClass> {

    private final Collection<E> myClass;

    public HolderClass() {
        myClass = new ArrayList<E>();
    }

    public void putSomeClass(final E clazz) {
        myClass.add(clazz);
    }

    public Collection<E> getMyClasses() {
        return myClass;
    }

} 

and you can make collection this way:

HolderClass<SomeSuperClass> holderClass = new HolderClass<SomeSuperClass>();
holderClass.putSomeClass(new SomeClass());
holderClass.putSomeClass(new SomeSuperClass());

and now, when you make call to getMyClasses(), you'll get collection of SomeSuperClasses

Tommy
A: 

.NET 4.0 introduces covariance and contravariance to generics:

http://msdn.microsoft.com/en-us/library/dd799517(VS.100).aspx

da_ponc
+3  A: 

Will Collection<? extends SomeSuperClass> not do what you want?

This is the correct way to go about this. See: http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html
Adam