Java通用返回类型问题

Java通用返回类型问题,java,generics,jvm,Java,Generics,Jvm,下面的Java代码中出现了一个非常奇怪的编译错误 我有一个简单的接口,它有一个具有通用返回类型的API: public interface AttributeGenerator { <T> T generateAttribute(Record record); } 现在,假设我在上面的接口中添加了另一个参数 public interface AttributeGenerator { <T> T generateAttribute(Record re

下面的Java代码中出现了一个非常奇怪的编译错误

我有一个简单的接口,它有一个具有通用返回类型的API:

public interface AttributeGenerator {

    <T> T generateAttribute(Record record);
}
现在,假设我在上面的接口中添加了另一个参数

public interface AttributeGenerator {

     <T> T generateAttribute(Record record, Set<Integer> indices);
}
公共接口属性生成器{
T生成属性(记录、设置索引);
}
我还提供了另一个实现:

public class StringAttributeGenerator implements AttributeGenerator {

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

}
公共类StringAttributeGenerator实现AttributeGenerator{
@凌驾
公共字符串generateAttribute(记录、设置索引){
返回“测试”;
}
}
编译失败,编译器投诉:

该方法不会从其超类重写


我无法理解为什么编译器不能编译第二个实例,如果不能,我想理解为什么Java不可能为用户提供编写此类代码的工具

问题是,在第一种情况下,您实际上禁用了泛型。在这种情况下,这将导致
T
被强制为
对象
,并且由于返回类型的协变量,返回
字符串
是可以的。但是,这应该会产生一个警告,因为您基本上是在强制编译器忽略泛型并使用“传统”方式,这相当于直接编写
对象生成属性(记录记录)

在第二种情况下,如果您以我上面描述的方式禁用泛型,则签名将类似于
generateAttribute(记录记录,设置索引)
,其中第二个参数将等效于
Set
,因此签名不再匹配

还请注意,虽然您的第一个代码段将被编译,但您可能会遇到运行时问题,例如,如果您这样做:

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 );
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";
  }
}
您可以在界面中定义
T
,例如:

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 );
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";
  }
}
公共接口属性生成器{
T生成属性(记录、设置索引);
}
公共类StringAttributeGenerator实现AttributeGenerator{
@凌驾
公共字符串generateAttribute(记录、设置索引){
返回“测试”;
}
}

问题是,在第一种情况下,您实际上禁用了泛型。在这种情况下,这将导致
T
被强制为
对象
,并且由于返回类型的协变量,返回
字符串
是可以的。但是,这应该会产生一个警告,因为您基本上是在强制编译器忽略泛型并使用“传统”方式,这相当于直接编写
对象生成属性(记录记录)

在第二种情况下,如果您以我上面描述的方式禁用泛型,则签名将类似于
generateAttribute(记录记录,设置索引)
,其中第二个参数将等效于
Set
,因此签名不再匹配

还请注意,虽然您的第一个代码段将被编译,但您可能会遇到运行时问题,例如,如果您这样做:

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 );
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";
  }
}
您可以在界面中定义
T
,例如:

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 );
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";
  }
}
公共接口属性生成器{
T生成属性(记录、设置索引);
}
公共类StringAttributeGenerator实现AttributeGenerator{
@凌驾
公共字符串generateAttribute(记录、设置索引){
返回“测试”;
}
}

第一段代码没有为我编译(JDK 1.8.0_60)@Tanuki奇怪!对我来说很好!您得到了什么错误?编译第一个代码段时,我得到:
类型安全:类型StringAttributeGenerator中generateAttribute(Record)的返回类型字符串需要取消选中转换以符合类型AttributeGenerator中的T
,但我在eclipse中将其设置为警告。第一个代码段代码没有为我编译(JDK 1.8.0_60)@Tanuki奇怪!它对我来说编译得很好!你得到了什么错误?编译第一个代码段,我得到:
Type safety:generateAttribute(Record)的返回类型字符串从类型StringAttributeGenerator需要取消选中转换以符合类型AttributeGenerator的T,但我在eclipse中将其设置为警告。我目前在JLS中找不到适合此主题的部分,因此如果有人愿意将其添加为注释,我会将链接放入答案中。实际上,我在站在最后一部分,这是一个实验。但这意味着如果我想失去返回类型的安全性,我也会失去泛型的方法参数的安全性!@bhuwanshani是的,你只能得到一个或另一个。但是如果你想牺牲返回类型的安全性(这可能会导致难以跟踪的bug)为什么不提供一个返回
Object
的方法,或者在接口中声明泛型类型,并在实现中将其定义为
Object
?此外,像您这样使用类型推断是非常危险的,因为您无法直接访问实现中的推断类型,因此您必须信任caller建议使用正确的类型。我目前无法在JLS中找到适合此主题的部分,因此,如果有人愿意将其添加为注释,我将在答案中添加链接。事实上,我理解最后一部分,这是一个实验。但这意味着如果我想失去返回类型的安全性,我也会失去met中的安全性泛型的hod参数!@bhuwanshani是的,你只能得到一个或另一个。但是如果你想牺牲返回类型的安全性(这可能会导致难以跟踪的bug)为什么不提供一个返回
Object
的方法,或者在接口中声明泛型类型,并在实现中将其定义为
Object
?此外,像您这样使用类型推断是非常危险的,因为您无法直接访问实现中的推断类型,因此您必须信任caller使用正确的类型。