2012-01-16 95 views
4

可能重复:
Why won't this generic java code compile?为什么这种(​​错误)使用Java泛型不能编译?

考虑下面的代码:

import java.util.Collections; 
import java.util.List; 

public class ComeGetSome { 
    //TODO: private final Some<?> some = new Some(); 
    private final Some some = new Some(); 

    public static void main(String[] args) { 
    new ComeGetSome().dude(); 
    } 

    public void dude() { 
    for (String str : some.getSomeStrings()) { //FIXME: does not compile! 
     System.out.println(str); 
    } 
    } 
} 

class Some<T> { 
    public List<String> getSomeStrings() { 
    return Collections.<String> emptyList(); 
    } 
} 

它不会编译,因为some.getSomeStrings()返回原始List。但方法签名指定它返回一个List<String>

不知何故,它涉及Some有一个类型声明,但被引用为原始类型的事实。使用对Some<?>的引用修复了此问题。但是这个方法与类中的类型声明无关!

为什么编译器的行为如此?

+0

Collections.emptyList ()? – 2012-01-16 23:23:04

+0

另请参阅http://stackoverflow.com/questions/1661068/java-generics-vanishing-type-in​​formation – 2012-01-16 23:24:21

回答

4

如果使用泛型类的原料(无类型)的实例,那么它被视为是完全原料,即所有泛型类型的信息被忽略,即使被忽略的类型是相关已省略的泛型类型。

这就是为什么这个......

private final Some<?> some = new Some(); 

...修正错误 - 它采用了类型版本的Some(尽管是一个通配符)

1

嗯,首先,它如果您实际上没有使用定义的类型参数,则声明Some类是没有意义的。这实际上是问题的根源。您实例化类型的成员字段在此FASION:

private final Some some = new Some(); 

这是一个原料类型的声明 - 这是一个通用型与它的类型参数冷落。这实际上不仅意味着它自己的类型参数T被丢弃,而且所有都忽略该类方法中使用的泛型类型,包括参数public List<String> getSomeStrings()中的<String>

因此,解决办法其实很简单,报价约书亚·布洛克:

不要在新的代码中使用的原始类型。

为了使这个混凝土,修复你的建议:

private final Some<?> some = new Some(); 

修复的问题,但实际上生成编译器警告(未经检查的操作)。该干净办法是,要么宣布的声明右侧的实际类型参数,如:

private final Some<String> some = new Some<String>(); 

你把泛型参数类型可以通过任何你想要的类型,它取决于你打算使用Some类的方式。但如果你真的不需要类型参数,只需删除它,代码会工作得很好:

class Some { ... } 

一个侧面说明:这是没有必要明确声明String参数在此代码:

return Collections.<String> emptyList(); 

编译器推断,从方法签名的泛型类型,这样可以简化代码这样:

public List<String> getSomeStrings() { 
    return Collections.emptyList(); 
    } 

编辑: 说起约书亚布洛赫的,有关于他的2011谷歌I/O谈这件事的实际一个很好的Java益智游戏:http://www.youtube.com/watch?v=wbp-3BJWsU8&t=36m04s

相关问题