简体   繁体   中英

Java Generic Return type Issue

I am getting a very weird compilation error in the below Java code.

I have a simple interface having an API with generic return type:

public interface AttributeGenerator {

    <T> T generateAttribute(Record record);
}

I can write an implementation and this one compiles fine:

public class StringAttributeGenerator implements AttributeGenerator {

     @Override
     public String generateAttribute(Record record) {
          return "Test";
     }
}

Now, lets say, I add another parameter to the above interface.

public interface AttributeGenerator {

     <T> T generateAttribute(Record record, Set<Integer> indices);
}

And I provide another implementation as:

public class StringAttributeGenerator implements AttributeGenerator {

     @Override
     public String generateAttribute(Record record, Set<Integer> indices) {
         return "Test";
     }

}

The compilations fails and compiler complaints that:

The method does not override from its superclass.

I cannot understand why the compiler is not able to compile the second instance, and if it is not, I would like to understand why is it not possible for Java to provide user a facility to write such a code.

AFAIK the problem is that in the first case you're actually disabling generics. This would result in T being coerced to Object in that case and due to return type covariace returning a String is fine. However, this should generate a warning since you're basically forcing the compiler to ignore generics and use the "traditional" way which would be equivalent to directly writing Object generateAttribute( Record record ) .

In the second case, if you disable generics in the way I described above the signature will look like generateAttribute(Record record, Set indices) where the second parameter would be equivalent to Set<Object> and thus the signature doesn't match anymore.

Also note that while your first snippet would compile you could get runtime problems, eg if you did something like this:

AttributeGenerator unknownGenerator = new StringAttributeGenerator();

//You'd get a string and the system would try to cast to Integer, which clearly will fail
Integer iWontCompile = unknownGenerator.generateAttribute( someRecord );

What you could do is define T in the interface, eg like this:

public interface AttributeGenerator<T> {
   T generateAttribute(Record record, Set<Integer> indices);
}

public class StringAttributeGenerator implements AttributeGenerator<String> {
 @Override
  public String generateAttribute(Record record, Set<Integer> indices) {
    return "Test";
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM