0

Note: This question may seem similar to Java generic method inheritance and override rules, but I'm interested in why declaring the type parameter at the class level causes the compilation to pass.

In the following code, StringMaker2 successfully compiles when it implements Maker2<String> However, StringMaker1 fails compilation when it implements Maker1 with:

GenericsTest.java: name clash: make(java.lang.Class<java.lang.String>) in GenericsTest.StringMaker1 and 
<T>make(java.lang.Class<T>) in GenericsTest.Maker1 have the same erasure, yet neither overrides the other

The only different between Maker1 and Maker2 is that that the type parameter, <T>, is defined at the method level in the former and class level in the later.

Could someone explain why this makes a difference?

public class GenericsTest {

    interface Maker1 {
        <T> T make(Class<T> type) throws Exception;
    }
    
    interface Maker2<T> {
        T make(Class<T> type) throws Exception;
    }
    
    // This class fails compilation
    class StringMaker1 implements Maker1 {

        @Override
        public String make(Class<String> type) throws Exception {
            return type.newInstance();
        }
    }
    
    class StringMaker2 implements Maker2<String> {

        @Override
        public String make(Class<String> type) throws Exception {
            return type.newInstance();
        }
    }
}
Pshemo
  • 122,468
  • 25
  • 185
  • 269
sweeteepee
  • 11
  • 2
  • The answer is in the error message: `public String make` does not override ` T make`. – Savior Nov 02 '20 at 22:15
  • I'm pretty sure you can't override methods like that. Interface `Maker1` declares a generic method; you can't change that without changing the method signature (which causes a compile error). Interface `Maker2` the *interface* is generic, not the method. Parameterizing the interface is OK so the method compiles. – markspace Nov 02 '20 at 22:17
  • You can't limit scope of acceptable method arguments while overriding it. Remember that subtypes can be assigned to variables of supertype like `Maker1 m1 = new StringMaker1();`. Since `m1` is of type `Maker1` it should allow user to call its ` T make(Class type)` method so it includes `Class` and any other class literals, not just `Class`. – Pshemo Nov 02 '20 at 22:29
  • In your `Maker1` interface, the type variable `` _is a parameter to the method_, and you can't change that signature when implementing. – chrylis -cautiouslyoptimistic- Nov 02 '20 at 22:32
  • Thank you to @markspace. The link to https://stackoverflow.com/questions/13049420/javahow-to-override-this-generic-method helped. As did @Pshemo explanation. I now understand how the StringMaker1 override incorrect restricts the signature of Maker1. In Maker2, the Type may be restricted by the implementing class but this keeps the signature valid. Because `Maker2 m = new StringMaker2()` passes compilation as the parameterized type agrees with the type of the `m` reference. – sweeteepee Nov 02 '20 at 22:38

0 Answers0