看看这三个班级。 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类,因为我也有非静态方法暴露给类扩展,我在问题中遗漏了。)
答案 0 :(得分:5)
静态方法不从类中获取泛型类型定义。即listAll()
方法不知道Lady
(extends 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)
由于类型擦除,这种情况正在发生。
实例化泛型类型时, 编译器通过转换这些类型 一种称为类型擦除的技术 - a 编译器删除所有的进程 与类型参数相关的信息 并在类或中键入参数 方法
因为正在对原始类型Minatchi执行调用Lady.ListAll,所以编译器无法知道特定类型是Minatchi
类型擦除用于泛型,因此泛型类型将与在将泛型添加到库之前编译的Java库兼容。已经有了reification added to Java的努力,但它不在Java 7的路线图上。