Reputation: 5624
I have a HashMap that links specific RequestTypes to separate LinkedLists. The lists consists of an interface with a generic type. I have no problems adding to the lists in the map but I can't seem to get the lists out of the map.
I'll show you two of my tries and there corresponding errors. First I'll show you the interface and my Map when I want to call the method in the interface.
public interface IRequestListener<Result> {
public void resultUpdated(Result result);
}
private HashMap<RequestType, LinkedList<IRequestListener<?>>> requestListenerMap =
new HashMap<RequestType, LinkedList<IRequestListener<?>>>();
In the following code, RequestType and Notification are two simple enums.
Here is the first try:
Notification notification = Notification.AVOID;
LinkedList<IRequestListener<?>> listeners =
requestListenerMap.get(RequestType.NOTIFICATION);
for(IRequestListener<?> listener : listeners) {
listener.resultUpdated(notification); // ERROR ON THIS LINE
}
That causes the following error:
The method resultUpdated(capture#1-of ?) in the type
IRequestListener<capture#1-of ?> is not applicable for
the arguments (Notification)
Here is the second try:
Notification notification = Notification.AVOID;
LinkedList<IRequestListener<Notification>> listeners =
requestListenerMap.get(RequestType.NOTIFICATION); // ERROR ON THIS LINE
for(IRequestListener<Notification> listener : listeners) {
listener.resultUpdated(notification);
}
That causes the following error:
Type mismatch: cannot convert from LinkedList<IRequestListener<?>>
to LinkedList<IRequestListener<Notification>>
I'm thinking that I'm getting tripped up by the inheritance/casting issues that are tricky with generics but I can't figure out how. I don't want to extend Notification since Result in the interface can be either a Notification or an Integer at this time. At a later time I might also add the possibility to have a List as a Result.
Cheers.
Upvotes: 0
Views: 246
Reputation: 1500215
It sounds like you want to constrain your Result
type parameter to extend Notification
:
private HashMap<RequestType, LinkedList<IRequestListener<? extends Notification>>>
requestListenerMap = new HashMap<>(); // Assuming Java 7
...
LinkedList<IRequestListener<? extends Notification>> listeners =
requestListenerMap.get(RequestType.NOTIFICATION);
for(IRequestListener<? extends Notification> listener : listeners) {
listener.resultUpdated(notification);
}
Now if that's not appropriate for the map declaration - because you'd want to store other lists for other entries - you may need an unsafe cast:
private HashMap<RequestType, LinkedList<IRequestListener<?>>> requestListenerMap =
new HashMap<RequestType, LinkedList<IRequestListener<?>>>();
...
LinkedList<IRequestListener<?>> listeners =
requestListenerMap.get(RequestType.NOTIFICATION);
for (IRequestListener<?> listener : listeners) {
// Note that this cast is unsafe.
IRequestListener<? extends Notification> notificationListener =
(IRequestListener<? extends Notification>) listener;
notificationListener.resultUpdated(notification);
}
Fundamentally you can't do this safely, as the execution-time type won't include the type argument. But you'll get a ClassCastException
when you call resultUpdated
if it's inappropriate.
Upvotes: 1