views:

51

answers:

4

Basic Java question here from a real newbie. I have a set of Java objects (of class "MyClass") that implement a certain interface (Interface "MyIfc"). I have a set of these objects stored in a private variable in my class that is declared as follows:

protected Set<MyClass> stuff = new HashSet<MyClass>();

I need to provide a public method that returns this set as a collection of objects of type "MyIfc".

public Collection<MyIfc> getMyStuff() {...}

How do I do the conversion? The following line gives me an error that it can't do the conversion. I would have guessed the compiler knew that objects of class MyClass implemented MyIfc and therefore would have handled it.

Collection<MyIfc> newstuff = stuff;

Any enlightenment is appreciated.

+1  A: 

You don't need to do any conversion. You will have to type your stuff as Set<MyIfc>.

Background: Yes, it is correct that if you have an object of type MyClass this will also be usable as a MyIfc instance. But you explicitly typed your Set as of type MyClass. And this is simply something different than a Set of type MyIfc. After all, you could also have other classes that implement MyIfcand then you could also put them into your Set<MyIfc> but not into Set<MyClass>.

Gerd Klima
This would be a great idea if I were able to not treat the members of the HashSet as MyClass. However, in my case I need to do that, so I prefer to leave the internal collection as it is.
HDave
+2  A: 

The compiler doesn't like your assignment of stuff to newstuff, because it lays open the possibility of putting things in newstuff that implement MyIfc but are not of type MyClass. You could have your getter create its own collection:

public Collection<MyIfc> getMyStuff() {
    Collection<MyIfc> coll = new HashSet<MyIfc>();
    coll.addAll(myStuff);
    return coll;
}
Nathan Hughes
I like this approach because I get to keep the collection of MyClass -- in this case I need to work with them as MyClass sometimes.
HDave
+1  A: 

Probably the most correct way is:

    return new HashSet<MyIfc>(stuff);

If the class is too large to do that, you can do:

    return Collections.unmodifiableSet(stuff);
Yishai
This has the same benefits as Nathan's approach above, but does it in one line via the constructor as opposed to calling "addAll". For that reason I think this is the best answer.
HDave
A: 

Google collections define a bunch of lazy adapters, that may be suitable for your purposes.

One in particular is Collections2.transform. Here is an example on how to adapt your collection:

Collection<MyIfc> newStuff =
  Collections2.transform(
    stuff,
    new Function<MyClass, MyIfc>( )
    {
      public MyIfc apply ( final MyClass from )
      {
        return (MyIfc) from; // This may throw a ClassCastException though
      }
    }
  )
Alexander Pogrebnyak
Seems like a very strange use of transform to me. Why not use stuff as a `Set<MyIfc>` internally. And beweare your code will return a live view which does *not* allow add/addAll.
Willi
I agree, it doesn't make sense to do all this.
Kevin Bourrillion