Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 874
Dale Wijnand Avatar asked Oct 01 '10 10:10

Dale Wijnand


People also ask

Can an interface implement a class?

Your class can implement more than one interface, so the implements keyword is followed by a comma-separated list of the interfaces implemented by the class. By convention, the implements clause follows the extends clause, if there is one.

How to implement the interface in Java?

The implements keyword is used to implement an interface . The interface keyword is used to declare a special type of class that only contains abstract methods. To access the interface methods, the interface must be "implemented" (kinda like inherited) by another class with the implements keyword (instead of extends ).

What type of members does an interface have Java?

An interface declaration introduces a new reference type whose members are classes, interfaces, constants and abstract methods. This type has no implementation, but otherwise unrelated classes can implement it by providing implementations for its abstract methods.


1 Answers

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.

like image 95
Jon Skeet Avatar answered Sep 20 '22 03:09

Jon Skeet