Java - 泛型类的类成员的行为

时间:2014-04-22 16:54:40

标签: java generics

如果在Java中将泛型类的实例声明为原始类型,编译器是否会为所有类成员方法假设参数化类型为Object?这是否会延伸到那些返回某种形式(例如Collection)具体参数化类型的方法?

我错误地声明了没有参数化类型的泛型类的实例,这导致了非常有趣的下游效果。我提供了一个简化的场景示例,该场景产生了“不兼容类型”编译错误。我的基本问题:为什么javac产生“不兼容类型”错误,抱怨下面的指示行?

import java.util.*;

public class Main {
    public static void main(String[] args) {
       final Test<String> t1 = new Test<String>(); 
       final Test t2 = new Test<String>();

       for (final Integer i : t1.getInts()) {
           System.out.println(i);
       }
       for (final Integer i : t2.getInts()) { //<-- compile-time error
           System.out.println(i);
       }
    }

    public static class Test<T> {
        public Test() {
        }

        public Set<Integer> getInts() {
            final Set<Integer> outSet = new HashSet<Integer>();
            outSet.add(new Integer(1));
            outSet.add(new Integer(2));
            outSet.add(new Integer(3));
            return outSet;
        }
    }
}

一个有趣的说明是,如果使用通配符类型(t2)声明Test<?> t2…,则代码将按预期编译并运行。

for-each循环的使用在next()返回的集合上的迭代器上调用getInts()(它返回从迭代的Iterable中收集的泛型类型)。 The documentation here提到如果Iterable是raw,则Object用作返回类型。为什么编译器似乎也将Test.getInts()的返回类型从Set<Integer>更改为Set<Object>

2 个答案:

答案 0 :(得分:5)

由于您使用了原始Test,因此Test类中的所有泛型都是有效类型删除的,甚至是不相关的泛型,例如返回Set<Integer>,因此Set<Integer> getInts返回的内容只是原始的Set。这就解释了为什么你会得到不兼容的类型,因为原始Set将返回Object,而不是Integer

Section 4.8 of the JLS涵盖原始类型:

  

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

  

原始类型的使用仅允许作为遗留代码兼容性的让步。在将泛型引入Java编程语言之后编写的代码中使用原始类型是非常不鼓励的。未来版本的Java编程语言可能会禁止使用原始类型。

(强调我的)

这种行为的原因是为了向前兼容pre-generics Java代码,因为内置Java类的pre-generics版本与generified内置类的原始类型版本相同。也就是说,pre-generics Set与原始Set相同(删除了泛型)。

答案 1 :(得分:0)

是的,在将变量声明为原始类型时(或当表达式解析为原始类型引用时),与该引用的所有交互都会像删除所有泛型一样。这包括通用参数列表类型和返回类型。