Java:在泛型类中使用类型变量

时间:2013-01-01 23:28:25

标签: java generics compilation

有人可以向我解释为什么这段代码无法编译?

即使它使用泛型类而不提供特定类型T,它应该能够在编译时识别ArrayList包含字符串。

public class Test {
    public static void main(String[] args){
        Container container = new Container();
        container.strings.add("test");
        String s1 = container.strings.get(0); // does not compile
        ArrayList<String> local = container.strings;
        String s2 = local.get(0); // does compile
    }

    static class Container <T>{
        ArrayList<String> strings = new ArrayList<String>();
    }
}

2 个答案:

答案 0 :(得分:7)

当您使用泛型类作为原始类型(未指定类型的类型)时,从类中删除所有通用信息(是否使用省略的类型)

因此,当您将代码Container container(而不是Container<SomeClass> containerArrayList<String> strings变为ArrayList strings时,就会将其视为ArrayList<Object>

要“修复”,请指定Container的类型(即使您不使用该类型):

Container<Object> container = new Container<Object>();

其余部分现在将编译。


这样做的原因是向后兼容早期的Java前通用版本(1.4及更早版本)

答案 1 :(得分:0)

正如波西米亚人所说,原始类型中的每个类型参数都被抛弃了。一开始我认为这是一个错误,但在bug database (#6244346)中甚至有一个条目明确引用了相关的JLS §4.8

  

构造函数的类型(第8.8节),实例方法(第8.4节,第9.4节),或者   非静态字段(第8.3节)未从中继承的原始类型C的M.   它的超类或超接口是对应的原始类型   在相应的通用声明中擦除其类型   下进行。

     

原始类型C的静态方法或静态字段的类型是   与其对应于C的通用声明中的类型相同。

     

将类型参数传递给非静态类型是编译时错误   原始类型的成员,不是从其超类继承的   超接口。

     

尝试使用a的类型成员是编译时错误   参数化类型作为原始类型。

您无法从原始String获取List但您可以将List分配给List<String>的原因是因为后者编译器发出警告(未经检查的转换)但你没有报告它(你读过警告吗,不是吗?:P)。我用javac和Eclipse编译器测试了你的代码,并且都尊重规范。

为了与遗留代码的互操作性而引入了原始类型,但在这种情况下,我无法弄清楚如何保持非静态成员的类型信息会破坏事物。使用参数化类型而不是原始类型意味着代码部分移植,因此在这种情况下,目的可能不仅仅是反向计算,而是确保连贯的代码库,代码满1.4或者完全是Java 5+。另一个选择是使用这样的原始类型可能会减慢在类似环境中采用无界通配符的速度。

顺便说一句(但我认为你自己想通了)如果你不使用type参数,你可以简单地使用一个无界的通配符,即Container<?>