Reputation: 10331
I don't understand why the compiler doesn't accept this code
import javax.swing.event.EventListenerList;
import java.util.EventListener;
public class GenericEventsManager {
EventListenerList listeners = new EventListenerList();
public <T extends EventListener> void addListener(T listener) {
listeners.add(listener.getClass(), listener);
}
}
The error I get is
The method add(Class<T>, T) in the type EventListenerList is not applicable for the arguments (Class<capture#1-of ? extends EventListener>, T)
The argument in addListener is of a type that extends EventListener, so listener.getClass() returns Class<? extends EventListener>
, which is exactly what the EventListenerList.add method expects
Can someone explain this? I have a feeling that it has something to do with getClass() not being resolved at compile time but it still doesn't make sense to me
Upvotes: 0
Views: 1442
Reputation: 360016
Generic parameters without wildcards are not variant and therefore require exactly the same types (not sub-types, not super types). (source)
The compiler simply will not let you do this. As the error message implies, the type parameter on the Class
parameter must be exactly the same as the type of the second argument, which is not true in the code above.
How can they not be identical?
Because the return type of listener.getClass()
is Class<? extends EventListener>
, not Class<T>
. You could — but I do not recommend doing so — cast the returned Class
to make this compile:
listeners.add((Class<T>)listener.getClass(), listener);
You'll get a compiler warning when doing so:
Type safety: Unchecked cast from Class<capture#1-of ? extends EventListener> to Class<T>
because this is not a (type)safe cast.
The root cause of this might (I'm honestly not sure) be simply poor API design in the declaration of EventListenerList#add()
. Typically PECS is used in this kind of situation; it's possible there's a good reason that add()
is not wildcarded.
Upvotes: 2
Reputation: 35106
Yes but in your add method you are specifying a Class<T>
, not a Class<EventListener>
Upvotes: 0