Java泛型扩展返回类型的方法

时间:2010-01-14 12:38:04

标签: java generics methods return-type

看看这三个班级。 Minatchi允许自己扩展,以便其方法的返回类型也可以扩展。为了说明,我使用了静态方法。

public class Minatchi<T extends Minatchi<?>>{

  static public <T extends Minatchi<?>>
    List<T> listAll(){
      return
        (List<T>) query();
  }
}

所以我把Minatchi子类化为Lady

public class Lady
extends Minatchi<Lady>{

}

这是可疑行为发生的地方。

public class HelloMinatchi{

  private void listA(){
    List<Lady> uvs = Lady.listAll();
    for (Lady uv: uvs){
      logger.info(uv.getName() );
    }
  }

  private void listB(){
    for (Lady uv: Lady.listAll()){
      logger.info(uv.getName() );
    }
  }
}

方法listA和listB基本相同。 listA将列表放入中间变量uvs, 而listB直接将listAll放入for循环标题。

但是,对于listB,编译器抱怨无法转换Minatchi&lt;?&gt;对夫人。

所以这个问题是关于Java泛型的设计完整性。另一个仿制药抱怨。

这是一个故意的设计功能还是Java仿制药设计人员不知道如何解决的无意设计错误。如果故意,他们为什么这样做?如果有bug,他们是否打算解决它?

或者这是我个人的问题,我不知道更好的方式来声明泛型?如果是这样,请告诉我如何。

(我使用了一个通用的Minatchi类,因为我也有非静态方法暴露给类扩展,我在问题中遗漏了。)

4 个答案:

答案 0 :(得分:5)

静态方法不从类中获取泛型类型定义。即listAll()方法不知道Ladyextends Minatchi<Lady>)。

它的返回类型由表达式的左侧推断:

    左侧的listA()中的
  • 定义了它预期List<Lady>
  • listB()中,forEach循环看起来也应该期望Lady,但看起来没有正确地指示编译器使用forEach循环。

使listB()工作的方法是告诉它使用哪种泛型:

for (Lady uv : Lady.<Lady>listAll()) {..}

答案 1 :(得分:1)

你的问题是你让编译器推断出listAll方法的泛型参数,并且在第一种情况下它推断出你想要的东西,因为你将结果存储在变量中,它只能查看变量的类型。在第二种情况下,它无法自动推断出“正确”类型,因此您需要自己指定:

for (Lady uv: Lady.<Lady>listAll()){
    logger.info(uv.getName() );
}

请注意,在此示例中,Minatchi类没有理由是通用的,因为它根本不会影响静态方法。

请注意,调用Lady.listAll与调用Minatchi.listAll完全相同(即它不会影响编译器可以或将推断为通用参数的类型)。

答案 2 :(得分:1)

不幸的是,正如我在另一个问题中提到的那样:Why implicit type inference only works in an assignment?,Java中的隐式类型推断仅适用于赋值。

我仍然不知道原因。不过,这对我来说似乎仍然很愚蠢。

答案 3 :(得分:1)

由于类型擦除,这种情况正在发生。

来自Java Generic tutorial

  

实例化泛型类型时,   编译器通过转换这些类型   一种称为类型擦除的技术 - a   编译器删除所有的进程   与类型参数相关的信息   并在类或中键入参数   方法

因为正在对原始类型Minatchi执行调用Lady.ListAll,所以编译器无法知道特定类型是Minatchi

类型擦除用于泛型,因此泛型类型将与在将泛型添加到库之前编译的Java库兼容。已经有了reification added to Java的努力,但它不在Java 7的路线图上。