Why does this override of a generic method work with 1.6, but not 1.7?
Given the following class, which overrides the getListeners method from AbstractListModel:
import java.util.EventListener;
import javax.swing.AbstractListModel;
public class GenericBug extends AbstractListModel {
/**
* This is the method of interest
* This is the exact same method signature that is present in the base class
*/
@Override
public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
// do something useful here...
return super.getListeners(listenerType);
}
// Not important here
@Override
public int getSize() {
return 0;
}
@Override
public Object getElementAt(int index) {
return null;
}
}
This class compiles fine using an Oracle 1.6 JDK. Trying the exact same class using an Oracle 1.7 JDK, I get compile errors saying there is a name clash, but the method isn't overridden (but it is!!)
Here is the error I get when I use JDK7:
% /usr/java/jdk1.7.0/bin/javac GenericBug.java
GenericBug.java:10: error: name clash: <T#1>getListeners(Class<T#1>) in GenericBug and <T#2>getListeners(Class<T#2>) in AbstractListModel have the 开发者_运维技巧same erasure, yet neither overrides the other
public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
^
where T#1,T#2 are type-variables:
T#1 extends EventListener declared in method <T#1>getListeners(Class<T#1>)
T#2 extends EventListener declared in method <T#2>getListeners(Class<T#2>)
GenericBug.java:12: error: incompatible types
return super.getListeners(listenerType);
^
required: T[]
found: EventListener[]
where T is a type-variable:
T extends EventListener declared in method <T>getListeners(Class<T>)
GenericBug.java:9: error: method does not override or implement a method from a supertype
@Override
^
Note: GenericBug.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
3 errors
Can someone explain to me what is happening? Is this a compiler bug in JDK1.7, or am I missing something?
First of all, AbstractListModel
is generic, you should not inherit it raw. If
class GenericBug extends AbstractListModel<Something>
the code compiles.
Now it is inherited raw, so what's happening? A raw type's instance methods all undergo erasure too [4.8], so the raw AbstractListModel
has a method
public EventListener[] getListeners(Class listenerType)
The GenericBug.getListeners
method in the subclass does not override this method[8.4.8.1].
This is based on JLS3, which Javac 6 should follow. So it must have been a Javac6 bug.
It appears that javac 7 has rewritten the type system algorithms, with a much better result.
JSL3: http://java.sun.com/docs/books/jls/third_edition/html/j3TOC.html
精彩评论