5

看看这三个类。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<?> 转换为 Lady。

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

这是 Java 泛型设计者不知道如何解决的故意设计特性还是无意的设计错误。如果是故意的,他们为什么要这样做?如果出现错误,他们是否打算解决它?

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

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

4

4 回答 4

5

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

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

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

工作的方法listB()是告诉它使用什么泛型类型:

for (Lady uv : Lady.<Lady>listAll()) {..}
于 2010-01-14T12:47:04.043 回答
1

不幸的是,正如我在另一个问题中提到的:为什么隐式类型推断只适用于赋值?, Java 中的隐式类型推断仅适用于赋值。

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

于 2010-01-14T12:51:45.973 回答
1

这是由于类型擦除而发生的。

来自Java 通用教程

当泛型类型被实例化时,编译器通过一种称为类型擦除的技术来转换这些类型——在这个过程中,编译器会删除与类或方法中的类型参数和类型参数相关的所有信息。

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

类型擦除用于泛型,以便泛型与在将泛型添加到库之前编译的 Java 库兼容。已经为将具体化添加到 Java做了一些努力,但它不在 Java 7 的路线图上。

于 2010-01-14T12:52:00.307 回答
1

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

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

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

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

于 2010-01-14T12:45:54.753 回答