I've got a problem with generic classes in java.
I've got this class:
public abstract class MyMotherClass<C extends AbstractItem>
{
private C item;
public void setItem(C item)
{
this.item = item;
}
public C getItem()
{
return item;
}
}
An implementation of this class can be:
public class MyChildClass extends MyMotherClass<ConcreteItem>
{
}
ConcreteItem is just a simple class that extends AbstractItem (which is abstract).
so MyChildClass have a ConcreteItem and I can use:
MyChildClass child = new MyChildClass();
child.setItem(new ConcreteItem());
// automatic cast due to generic class
ConcreteItem item = child.getItem();
Ok, all is fine for the moment. Here is the problem:
Now I want to extract from a collection an instance of MyMotherClass and set its item (which type is not known):
Map<String, MyMotherClass> myCollection = new HashMap<String, MyMotherClass>();
Map<String, AbstractItem> myItems = new HashMap<String, AbstractItem>();
// fill the 2 collections
...
MyMotherClass child = myCollection.get("key");
child.setItem(myItems.get("key2"));
If I do like this, it runs. BUT I have warning because MyMotherClass is a generic type and I don't use the generic type. But I don't know which is the type of my extracted child, so I want to use a wildcard:
Map<String, MyMotherClass<?>> myCollection = new HashMap<String, MyMotherClass<?>>();
Map<String, AbstractItem> myItems = new HashMap<String, AbstractItem>();
// fill the 2 collections
...
MyMotherClass<?> child = myCollection.get("key");
child.setItem(myItems.get("key2"));
And here is the problem: I've got a compilation error which says: The method setItem(capture#1-of ?) in the type MyMotherClass is not applicable for the arguments (AbstractItem)
and when I try with an inherited wildcard, same problem:
Map<String, MyMotherClass<? extends AbstractItem>> myCollection = new HashMap<String, MyMotherClass<? extends AbstractItem>>();
Map<String, AbstractItem> myItems = new HashMap<String, AbstractItem>();
// fill the 2 collections
...
MyMotherClass<? extends AbstractItem> child = myCollection.get("key");
child.setItem(myItems.get("key2"));
what can I do ?
thanks and sorry for my english which is not very fluent ;)
I might be missing something, but why not do the following in your MyMotherClass class, using the explicit class AbstractItem
rather than the generic class C
?
public abstract class MyMotherClass<C extends AbstractItem> {
private AbstractItem item;
public void setItem(AbstractItem item) {
this.item = item;
}
public AbstractItem getItem() {
return this.item;
}
}
This change alone would allow you to use your wildcard approach:
Map<String, MyMotherClass<?>> myCollection = new HashMap<String, MyMotherClass<?>>();
Map<String, AbstractItem> myItems = new HashMap<String, AbstractItem>();
// fill the 2 collections
MyMotherClass<?> child = myCollection.get("key");
child.setItem(myItems.get("key2"));
with no errors.
Of course, in MyChildClass
, you can then override MyMotherClass#getItem()
as follows:
@Override
public ConcreteItem getItem() {
return (ConcreteItem) super.getItem();
}
to make sure that the right class is being returned; this same approach for all subclasses of MyMotherClass
would allow you to return the right types.