简体   繁体   English

Java通用返回类型问题

[英]Java Generic Return type Issue

I am getting a very weird compilation error in the below Java code. 我在下面的Java代码中收到一个非常奇怪的编译错误。

I have a simple interface having an API with generic return type: 我有一个简单的接口,具有具有通用返回类型的API:

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. 我不明白为什么编译器不能编译第二个实例,如果不是,我想理解为什么Java无法为用户提供编写此类代码的便利。

AFAIK the problem is that in the first case you're actually disabling generics. AFAIK问题在于,在第一种情况下,您实际上是在禁用泛型。 This would result in T being coerced to Object in that case and due to return type covariace returning a String is fine. 在这种情况下,这将导致T被强制转换为Object ,并且由于返回类型为协方差,因此返回String是可以的。 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 ) . 但是,这应该会产生警告,因为您基本上是在迫使编译器忽略泛型并使用“传统”方式,这相当于直接编写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. 在第二种情况下,如果以上述方法禁用泛型,则签名将看起来像generateAttribute(Record record, Set indices) ,其中第二个参数等效于Set<Object> ,因此签名不再匹配。

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: 您可以在接口中定义T ,例如:

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";
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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