views:

85

answers:

4

I have the following test code:

public interface Container<I> {
    public void addClass(Class<?> clazz);
}

public class MyContainer implements Container {
    public void addClass(Class<?> clazz) {}
}

and I get the following error when trying to compile these two class:

MyContainer.java:1: MyContainer is not abstract and does not override abstract method addClass(java.lang.Class) in Container

If I add a type to the Container interface in MyContainer (such as <Object>), I don't get the error.

The problem is I'm introducing the type parameter to Container, which is part of the public API, so for compatibility, I can't have all implementing classes unable to compile.

Anyone have any ideas? Is it a type erasure issue? Is there a workaround?

Thank you

+7  A: 

I think the problem is that if you use raw types anywhere in the class declaration, you're sort of opting out of generics. So this will work - note the parameter change.

public class MyContainer implements Container {
    public void addClass(Class clazz) {}
}

From section 4.8 of the JLS:

The superclasses (respectively, superinterfaces) of a raw type are the erasures of the superclasses (superinterfaces) of any of its parameterized invocations.

I believe that's the relevant bit... the erasure of Container<T>.addClass(Class<?> clazz) is addClass(Class clazz).

But yes, basically unless this is genuine legacy code, you should regard introducing a type parameter into an interface as a breaking change.

Jon Skeet
@Skeet- elaboration would be helpful..TIA
hakish
I see, thank you Jon. Accepted.
Dale Wijnand
+3  A: 

Getting rid if the <?> fixes it:

public void addClass(Class clazz) {}

The error message is not very descriptive:

Name clash: The method addClass(Class) of type MyContainer has the same erasure as addClass(Class) of type Container but does not override it

This would mean that both your methods are the same when their types are erased, but the subclass method does not actually implement/override the one from the superclass/interface. This does not make much sense, and I would assume that it's because you have chosen not to use generics in your subclass, you have to stick to that (and not perameterize Class)

Bozho
+3  A: 

If your class uses Generics then a simple solution would be to do this :

interface Container<I> {
    public void addClass(Class<?> clazz);
}

class MyContainer<I> implements Container<I> {
    public void addClass(Class<?> clazz) {}
}

Or if you already know the type of Container you have,

class MyContainer implements Container<ContainerType> {
    public void addClass(Class<?> clazz) {}
}

If your class doesn't use Generics (pre 1.5) then you can't have the <?> part. So there won't be any real problem here.

class MyContainer implements Container {
    public void addClass(Class clazz) {}
}
Colin Hebert
+1  A: 

Implementing your interface as follows should work (as per type erasure):

public class MyContainer implements Container {
    public void addClass(Class clazz) {}
}
Faisal Feroz