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:
- Why does adding a type parameter to a method prevent it from overriding an unparameterized method in its superclass?
- Is there a better way to get the behavior I want?
Advertisement
Answer
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.