Search code examples
javagenericsoverridingtype-erasuretype-parameter

Cannot compile a class which implements an interface without type parameter


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?


Solution

  • 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.