0
votes

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?

1
This may be a bug in netbeans. Eclipse does not complain about this code at all, so the issue isn't inherent to Java. I'd generally try to avoid overloads like this though. - Don Roby
Aw, bugger if it is. I'll see if I can find if this is a known bug in Netbeans... Thanks. - Ghostkeeper
It seems to be inherent in Java after all. I don't know why Eclipse doesn't complain, but javac gives me the same error. - Ghostkeeper
The fix is easy. Just use different names for the different methods. There's no reason to name them the same. - Don Roby
Perhaps you're right, and I would rename the method as a last resort, but I'd still like to know the reason why this is disallowed. I tried to do it this way for clarity's sake, which is important in writing good interfaces. - Ghostkeeper

1 Answers

3
votes

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.