I need to implement a method from a class Foo
, in my subclass Bar
:
class Foo {
public abstract void foo();
}
class Bar extends Foo {
private <T> Map<T, List<T>> getStuff() { ... }
@Override
public void foo() {
Map<?, List<?>> stuff = getStuff();
for (Entry<?, List<?>> e : stuff.entrySet()) {
Object key = e.getKey();
List<?> lst= e.getValue();
lst.add(key); // illegal: need ?, got Object
}
}
}
As you can see, my method would benefit from a type parameter:
@Override
public <T> void foo() {
Map<T, List<T>> stuff = getStuff();
for (Entry<T, List<T>> e : stuff.entrySet()) {
T key = e.getKey();
List<T> lst= e.getValue();
lst.add(key); // legal!
}
}
(I could also use raw types because I know it'll work, but everything I've read says you really shouldn't do that)
Unfortunately, this is illegal - my method foo
in Bar
"clashes with foo() in Foo; both methods have the same erasure, yet neither overrides the other".
Which seems odd, given that my type parameter does not alter the parameters or return type of foo
- any place it is okay to use Foo.foo
in, it is also okay to use my (illegal) Bar.foo
in.
My ugly hack of a workaround has, up until this point, been to just write a whole new (parameterized) method:
public void foo() {
realFoo();
}
private <T> void realFoo() {
// parameterized version of .foo() above
}
I have two questions:
See JLS 8.4.2:
8.4.2. Method Signature
Two methods or constructors, M and N, have the same signature if they have the same name, the same type parameters (if any) (§8.4.4), and, after adapting the formal parameter types of N to the the type parameters of M, the same formal parameter types.
The signature of a method m1 is a subsignature of the signature of a method m2 if either:
- m2 has the same signature as m1, or
- the signature of m1 is the same as the erasure (§4.6) of the signature of m2.
Two method signatures m1 and m2 are override-equivalent iff either m1 is a subsignature of m2 or m2 is a subsignature of m1.
Because type parameters are part of the method signature, you can't add or remove type parameters in overriding methods.
My ugly hack of a workaround...
Yes, it's ugly, but this is the right way to do it.