2010-01-14 88 views
5

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

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

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

于是我继承Minatchi到夫人

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, 而列表B直接将listAll放入for-loop标头。

但是,对于listB,编译器抱怨无法将Minatchi <?>转换为Lady。

所以这个问题是关于Java泛型的设计完整性。还有另一种泛型抱怨。

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

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

(我使用的通用Minatchi类,因为我已非静态方法暴露于类扩展过,这是我在这个问题排除在外。)

+0

我使用了一个通用的Minatchi类,因为我有非静态方法也暴露给类扩展,我忽略了题。 – 2010-01-14 13:17:07

回答

5

静态方法不接受类中的泛型类型定义。即listAll()方法不知道Lady(在extends Minatchi<Lady>中)。

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

  • listA()左手侧限定,它预计List<Lady>
  • listB() foreach循环看起来也应该期望Lady,但似乎编译器没有正确指示forEach循环。

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

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

感谢bozho。我在吸烟什么? – 2010-01-14 12:57:14

1

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

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

请注意,在这个例子中,我们没有理由对Minatchi类是通用为不完全影响静态方法。

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

+0

女士。 listAll(),而不是Lady.listAll ();)(更正它为你) – Bozho 2010-01-14 12:49:14

+0

如果编译器可以从一个变量推断,它肯定应该没有问题推断从for循环头变量的类型。 for(Lady uv:Lady.listAll()) 这个问题不是关于如果我应该使用中间变量。相反,这是为什么语言设计者忘记了容纳for循环?为什么他/他们不能使用for循环变量? IOW,他们在吸烟? – 2010-01-14 12:53:00

+0

谢谢。我应该在发布之前进行测试。 – sepp2k 2010-01-14 12:53:16

1

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

Java Generic tutorial

当一般类型被实例化, 编译器通过 翻译这些类型的技术称为类型擦除 - 一个 方法,其中,编译器将删除输入参数 相关所有 信息和在类中输入参数或 方法。

,因为呼叫Lady.ListAll的原始类型Minatchi执行时,编译器无法知道具体的类型是Minatchi使用

类型消除仿制药,使泛型类型是兼容在将泛型添加到库之前编译Java库。已经有一些努力来拥有reification added to Java,但它并不在Java 7的路线图中。

+0

真的吗?我认为类型擦除只发生在运行时。这个错误出现在编译时。 – nanda 2010-01-14 12:53:36

+0

@nanda:类型擦除处于编译时 - 如果类型在运行时已知,则不需要擦除它。 – 2010-01-14 12:54:51

+0

我的意思是,删除是在编译时,所以运行时不知道泛型类型,但是在编译类之前出现错误检查。如果它有错误,它如何被编译? – nanda 2010-01-14 12:58:40