tags:

views:

51

answers:

3

I have a data type that contains a set and a method that expects List<? extends MyClass>. The data type has Set<? extends MyClass>. I need to be able to move the stuff out of the set and into the List. The order it goes into the list doesn't matter, it just needs to start keeping track of it so that it can be reordered when displayed. Suffice to say that changing the Set into a List in the data type is out of the question here.

This seems pretty easy at first. Create a new method that takes a Set instead of a List, changes it into a list and then passes it on to the old method that just took a list. The problem comes in changing the set to a list.

public void setData(Set<? extends MyClass> data) {
    List<? extends Myclass> newData = ArrayList< /* What goes here? */ >();
    for(ConcordaEntityBean o : data) {
        newData.add(o);
     }
     setData(newData);
}

Obviously, I can't instantiate an ArrayList with a wildcard, it chokes. I don't know the type at that point. Is there some way to pull the type out of data and pass it to ArrayList? Can I just instantiate it with MyClass? Is there some other way to do this?

+1  A: 

Does this work:

List<MyClass> newData = new ArrayList<MyClass>(data);
setData(newData);

?

Or even a one-liner:

setData(new ArrayList<MyClass>(data));
Kip
+6  A: 

You can't instantiate it with MyClass because newData is not necessarily of type List<MyClass>, and Java does not support covariance (ie, S extends T does not imply that ArrayList<S> is a subtype of ArrayList<T>).

What you can do is this:

List<MyClass> newData = new ArrayList<MyClass>();

Now, everything in the Set (which is guaranteed to be a subtype of MyClass) can be put into newData.

Generally speaking, wildcard types enforce boundary constraints. You know that Set<? extends MyClass> is a Set parameterized with some type, and that type is bounded from above by MyClass. So when you are dealing with the elements from that Set, you can do no better than to treat them as MyClass objects.

danben
The other option I found that worked, was to simply have the class in question take T as a class parameter. Which for this instance - while it required more refactoring than I liked, worked. This is better though. Less refactoring.
Daniel Bingham
A better reason not to do that is that (maybe) this method is not supposed to be parameterized. It depends on whether you want `setData` to operate on all `Set`s, or only `Set`s of `MyClass` (and its subtypes).
danben
@danben Well, I could always parameterize the class to only take types that extend MyClass (T extends MyClass).
Daniel Bingham
A: 

I know my grasp of writing generic methods is shaky, but it seems like this would work:

public <T extends MyClass> void setData(Set<T extends MyClass> data) {
    setData(new ArrayList<T>(data));
}
R. Bemrose
Close: public <T extends MyClass> setData(Set<T> data). But the setData that takes a list would also have to have the same kind of generics in the signature.
Yishai