Reputation: 4949
I have a LinkedHashSet of values of ThisType. ThisType is implementing the interface ThatType.
I need the polymorphic use of this collection-- be able to point to it as LinkedHashSet< ThatType >.
How is this done?
i know this is a naive question, but several things i tried didn't work, and i wanna do it the right way.
Thanks in advance.
//==============================
UPDATE: more details:
In the following code, ThisType implements ThatType-- ThatType is an interface.
//LinkedHashMap<Integer, ? extends ThatType> theMap = new LinkedHashMap<>();
LinkedHashMap<Integer, ThisType> theMap = new LinkedHashMap<>();
for (Integer key:intArray) {
ThisType a = new ThisType();
if (theMap.containsKey(key)) {
a = theMap.get(key);
a.doStuff();
} else {
a.doOtherStuff();
}
theMap.put(key, a);
}
In the end, i wanna return the theMap as a collection of ThatType **, not **ThisType.
this is where the chain is broken. using the commented line (first line) for declaration is giving type mismatch error on put() & get() methods of the hash.
not sure whether this is significant-- but, i'm returning the result as LinkedHashSet< ThatType >. i'm doing the conversion from LinkedHashMap to LinkedHashSet. However, nothing worked nowhere for the polymorphic reference to collection values in the map or set. All and only type i used in all these operations so far is ThisType. ThatType gave me some error just about anywhere i tried it.
Upvotes: 0
Views: 144
Reputation: 280174
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
.
Upvotes: 1
Reputation: 21981
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{
}
Upvotes: 0
Reputation: 83393
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;
}
Upvotes: 2