Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding a Generic allows you to override a method with a different return type?

Tags:

java

generics

I ran into this today and the only thing I can think is that this is a bug in the Java compiler. The following code compiles, but certainly seems incorrect (since testMethod has a differenet signature in the child but overrides the parent) and will throw class cast exceptions at runtime.

public interface TestInterface<T> {
  public List<String> testMethod(); // <-- List<String>
}
public class TestClass implements TestInterface {
  @Override
  public List<Integer> testMethod() { // <-- List<Integer> overriding List<String>!!
      return Collections.singletonList(1);
  }
}

And using the above structure:

public void test() {
  TestInterface<Boolean> test = new TestClass();
  List<String> strings = test.testMethod();
  for (String s : strings) {
    System.out.println(s);
  }
}

All of this compiles fine, but will obviously throw class cast exceptions if you run it.

If you remove <T> from TestInterface, or fill T in in the line TestClass implements TestInterface<T> then the code will no longer compile, which makes sense. Imo <T> should have no bearing on the compilation of testMethod since it plays no part in that method. Maybe adding <T> to TestInterface is causing the compiler to type-erase the method signatures even though T doesn't participate in those methods...?

Does anyone know what is going on here?

like image 306
Matt Wonlaw Avatar asked Mar 28 '11 17:03

Matt Wonlaw


1 Answers

If you instantiate a generic class as a raw type, all generic type parameters contained in it are going to be omitted by the compiler, hence it gives you no warnings/errors during compilation. I.e. declaring

public class TestClass implements TestInterface ...

effectively degrades the code into

public interface TestInterface {
  public List testMethod();
}
public class TestClass implements TestInterface {
  @Override
  public List testMethod() {
      return Collections.singletonList(1);
  }
}

which indeed compiles fine.

A similar problem was posted a couple of weeks ago, the answer to which stating that it is not a compiler bug, rather a deliberate design decision for backward compatibility.

like image 85
Péter Török Avatar answered Oct 11 '22 23:10

Péter Török