I have a LinkedHashSet of values of ThisType. ThisType is implementing the interface ThatType.
I ne
When you declare a wildcard bounded type argument as in
LinkedHashMap<Integer, ? extends ThatType> theMap = new LinkedHashMap<>();
you are telling the compiler that the type argument can be any class that is a sub type of ThatType
. Imagine this case
LinkedHashMap<Integer, ? extends ThatType> theMap = getLinkedHashMap();
where getLinkedHashMap()
is defined as
public LinkedHashMap<Integer, OtherType /* which implements ThatType */> getLinkedHashMap();
The previous assignment would work because OtherType
is a sub type of ThatType
. However, you could not then expect
ThisType a = theMap.get(key);
to work. Because of the wildcard, all you know is that the map definitely contains ThatType
instances (called the upper bound), but they could be of type OtherType
or ThatType
(or other sub type of ThatType
). At most you could do
ThisType a = (ThisType) theMap.get(key);
casting the return value, but then you are opening yourself up to ClassCastException
.
Similarly, you cannot call put()
with anything other than than null
.
theMap.put(someInt, null); // will compile
theMap.put(someInt, new ThisType()); // will not compile
theMap.put(someInt, new OtherType()); // will not compile
The compiler doesn't let you add anything because it can't guarantee what the map contains, again because of the wildcard bound. But null can be used because
The null reference can always undergo a widening reference conversion to any reference type.
So null
is a valid argument because it is the lower bound of the wildcard.
You're in a special situation where, it seems, your method creates the LinkedHashMap
internally and you know what you will be passing to it. Therefore you can do the following
public static LinkedHashMap<Integer, ThatType> getTheSet(int[] intArray) {
LinkedHashMap<Integer, ThatType> theMap = new LinkedHashMap<>();
for (Integer key : intArray) {
ThisType a = new ThisType();
if (theMap.containsKey(key)) {
a = (ThisType) theMap.get(key); // cast it because you know they will definitely be `ThisType` references
a.doStuff();
} else {
a.doOtherStuff();
}
theMap.put(key, a);
}
return theMap;
}
Since ThisType
is a sub type of ThatType
, you can put instances of ThisType
into the map. You need to be careful how you then use this method's returned value. All the compiler knows about the return value is that it contains ThatType
references. It doesn't know that they are actually ThisType
.
You need the wildcard of Set<? super ThisType>
. Look at following example
public static void main(String[] args) {
Set<ThatType> set=new LinkedHashSet<>();
Set<ThisType> set2=new LinkedHashSet<>();
someFunction(set);
someFunction(set2);
}
static void someFunction(Set<? super ThisType> set) {
}
class ThisType implements ThatType{
}
interface ThatType{
}
I think what you want is to use wildcards.
LinkedHashSet<? extends ThatType> someFunction(LinkedHashSet<? extends ThatType> set) {
return set;
}
As has been explained elsewhere LinkedHashSet<ThisType>
is not a subclass of LinkedHashSet<ThatType>
, since LinkedHashSet<ThisType>
can't accept ThatType
objects.
The wildcard in LinkedHashSet<? extends ThatType>
means a LinkedHastSet
of some class (not sure what) that extends ThatType
.
Though you may want to consider using this:
Set<? extends ThatType> someFunction(Set<? extends ThatType> set) {
return set;
}