Could anyone explain to me why this is not allowed in Java? I have these three files (stripped and simplified for StackExchange):
A superclass, in my case for generic graphs. The type parameter indicates how arcs are represented: Either with a specific Arc class, or with Integers indicating unique IDs.
public interface Base<A> {
public boolean removeArc(A arc);
}
A subclass, with a specific implementation for arc.
public interface Sub<B> extends Base<Arc<B>> {
@Override
public boolean removeArc(Arc<B> arc);
public Arc<B> removeArc(B value); //Removes an arc with this specific value.
}
The arc implementation.
public interface Arc<B> {
}
Netbeans gives me the following compile-time errors in Sub. At @Override:
name clash: removeArc(Arc<B>) in Sub overrides a method whose erasure is the same as another method, yet neither overrides the other
first method: removeArc(B) in Sub
second method: removeArc(A) in Base
where B,A are type-variables:
B extends Object declared in interface Sub
A extends Object declared in interface Base
At the second method:
name clash: removeArc(B) in Sub and removeArc(A) in Base have the same erasure, yet neither overrides the other
where B,A are type-variables:
B extends Object declared in interface Sub
A extends Object declared in interface Base
The problem seems to be that removeArc(Arc<B>)
and removeArc(B)
have the same erasure, but I don't see why this is happening. Removing removeArc(Arc<B>)
compiles fine, without warning about the @Override
, so it must realise that Arc<B>
equals A
in Base
.
Why is Java unable to differentiate between Arc<B>
and B
in this case?
The compiler removes generic classes at compile time. It will replace the place holder with it's restricted class.
In this case Base
will replace any instance of A
with Object
and Sub
will replace any instance of B
with Object
.
this gives the conflicting methods
in Base public boolean removeArc(Object arc);
and in Sub public Arc removeArc(Object value);
if however you did
public interface Base<A extends Arc<?>> {
public boolean removeArc(A arc);
}
then the instances of A
would be replaced with Arc
and the method signatures would no longer conflict.