I'm trying to understand the name clash error I get with the following code:
import java.util.*;
import javax.swing.*;
class Foo<R extends Number> {
public void doSomething(Number n, Map<String, JComponent> comps) {
}
}
class Bar extends Foo {
public void doSomething(Number n, Map<String, JComponent> comps) {
}
}
Error message:
error: name clash:
doSomething(Number,Map<String,JComponent>)
inBar
anddoSomething(Number,Map<String,JComponent>)
inFoo
have the same erasure, yet neither overrides the other
I know I can fix it by either remove the generic type from Foo
, or by changing the Bar
declaration to class Bar extends Foo<Integer>
; what I want to know is why this error occurs in the specific case, but goes away if I remove the comps
parameter from each method. I've done some reading about type erasure, but it still appears to me that both methods should have the same erasure with or without generics, and therefore be a valid override in either case. (Note that I haven't even used the generic parameter anywhere yet, which is why I'm so surprised.)
I know that I've added generic types to parent classes before but only got warnings about the subclasses, not errors. Can anyone explain this scenario?
Luiggi is right in the comments. This is a consequence of raw types.
This applies when invoking a supertype method, but also when overriding one.
Take for example, the following
You'll notice that it compiles, even though
HashMap<Number, String>
is not a type that is assignable toMap<String, JComponent>
.(Note that
C
in our case isBar
.)And the same thing happens when trying to override a method. When trying to override the
Foo#doSomething(..)
method, yourBar
class is actually seeing it declared asIn other words, every usage of type parameters is erased. So attempting to declare the method
in the subtype
Bar
is actually an attempt at overloading, not overriding. And this fails because of type erasure. The proper override, which you can verify with@Override
, isFurther reading: