简体   繁体   English

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

[英]Java: using typed variables in a generic class

Could someone please explain to me why this piece of code does not compile? 有人可以向我解释为什么这段代码不能编译?

Even though it uses a generic class without providing the specific type T, it should be able to recognize at compile time that the ArrayList holds strings. 即使它使用泛型类而不提供特定类型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>();
    }
}

When you use a generic class as a raw type (one where you don't specify a type), ALL generic information is stripped from the class (whether the omitted type is used or not). 当您使用泛型类作为原始类型(未指定类型的类型)时, 将从类中剥离所有通用信息 (是否使用省略的类型)。

So when you code Container container (instead of Container<SomeClass> container ) ArrayList<String> strings becomes ArrayList strings , which is used as if it were ArrayList<Object> . 因此,当您对Container container (而不是Container<SomeClass> container )进行编码时, ArrayList<String> strings将成为ArrayList strings ,其使用方式就像它是ArrayList<Object>

To "fix", specify the type for Container (even though you don't use the type): 要“修复”,请指定Container的类型(即使您不使用该类型):

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

the rest will now compile. 其余的将现在编译。


The reason this is done is to be backward compatible with earlier pre-generic versions of java (1.4 and earlier) 这样做的原因是向后兼容早期的Java前通用版本(1.4及更早版本)

As Bohemian said, every type argument in a raw type is thrown away. 正如波西米亚人所说,原始类型中的每个类型参数都被抛弃了。 At the beginning I thought it was a bug, but there's even an entry in the bug database (#6244346) which explicitely quotes the relevant JLS §4.8 一开始我觉得这是一个bug,但是在bug数据库(#6244346)中甚至还有一个条目明确引用了相关的JLS§4.8

The type of a constructor (§8.8), instance method (§8.4, §9.4), or non-static field (§8.3) M of a raw type C that is not inherited from its superclasses or superinterfaces is the raw type that corresponds to the erasure of its type in the generic declaration corresponding to C. 未从其超类或超接口继承的原始类型C的构造函数(第8.8节),实例方法(第8.4节,第9.4节)或非静态字段(第8.3节)M的类型是对应的原始类型在对应于C的通用声明中擦除其类型

The type of a static method or static field of a raw type C is the same as its type in the generic declaration corresponding to C. 原始类型C的静态方法或静态字段的类型与其对应于C的泛型声明中的类型相同。

It is a compile-time error to pass type arguments to a non-static type member of a raw type that is not inherited from its superclasses or superinterfaces. 将类型参数传递给未从其超类或超接口继承的原始类型的非静态类型成员是一个编译时错误。

It is a compile-time error to attempt to use a type member of a parameterized type as a raw type. 尝试将参数化类型的类型成员用作原始类型是编译时错误。

The reason why you can't get a String from a raw List , but you can assign a List to a List<String> is because in the latter the compiler issues a warning ( unchecked conversion ) but you don't report it (do you read warnings, don't you? :P). 您无法从原始List获取String的原因,但是您可以将List分配给List<String> ,因为在后者中编译器会发出警告( 未经检查的转换 ),但您不报告它(执行你看了警告,不是吗?:P)。 I tested your code with javac and the Eclipse compiler, and both honor the spec. 我用javac和Eclipse编译器测试了你的代码,并且都遵守规范。

Raw types were introduced for interoperability with legacy code, but in this case I can't figure out a way how keeping type information for non-static members would have break things. 引入了原始类型以便与遗留代码进行互操作,但在这种情况下,我无法弄清楚如何保留非静态成员的类型信息会破坏事物。 Using a parameterized type instead of a raw type would mean code partially ported , so maybe in this case the purpose is not simply backcompat, but ensuring a coherent codebase, either the code is full 1.4, or it's entirely Java 5+. 使用参数化类型而不是原始类型意味着代码部分移植 ,因此在这种情况下,目的可能不仅仅是反向计算,而是确保连贯的代码库,代码是完整的1.4,或者它完全是Java 5+。 Another option is that using raw types like this may have slowed down the adoption of unbounded wildcards in similar contexts. 另一个选择是使用这样的原始类型可能会减慢类似上下文中无界通配符的采用速度。

BTW (but I think you figured it out by yourself) you can simply use an unbounded wildcard if you don't use the type parameter, ie Container<?> BTW(但我认为你自己想通了)如果你不使用type参数,你可以简单地使用一个无界的通配符,即Container<?>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM