通用类型擦除警告

时间:2014-08-27 14:33:07

标签: java generics

我从 Thinking in Java 这本书中获得了这段代码,其中Bruce表示调用方法 set()的警告。代码如下:

    package testPackage;

    class GenericBase<T> {
    private T element;
    public void set(T arg) { arg = element; }
    public T get() { return element; }
    }
    class Derived1<T> extends GenericBase<T> {}
    class Derived2 extends GenericBase {} // No warning
    // class Derived3 extends GenericBase<?> {}
    // Strange error:
    // unexpected type found : ?
    // required: class or interface without bounds
    public class ErasureAndInheritance {
    @SuppressWarnings("unchecked")
    public static void main(String[] args) {
        Derived2 d2 = new Derived2();
        Object obj = d2.get();
        d2.set(obj); // Warning here!
        }
    }

如果删除注释,我会收到以下警告:
类型安全:方法集(Object)属于原始类型GenericBase。对泛型类型GenericBase的引用应该参数化

我的问题是,为什么警告会显示在 set()方法上?有人可以解释这个警告的含义吗? 顺便说一句,我是Java Generics的新手,虽然我读了关于泛型的其他问题,但我仍然对 Erasure 感到困惑。

1 个答案:

答案 0 :(得分:3)

来自Java doc here

  

泛型被引入Java语言以提供更紧密的类型   在编译时检查并支持通用编程。至   实现泛型,Java编译器将类型擦除应用于:

     
      
  • 如果类型参数是无界的,则将泛型类型中的所有类型参数替换为其边界或对象。生成的字节码,   因此,只包含普通的类,接口和方法。
  •   
  • 如有必要,插入类型转换以保护类型安全。
  •   
  • 生成桥接方法以保留扩展泛型类型中的多态性。
  •   
  • 类型擦除确保不为参数化类型创建新类;因此,泛型不会产生运行时开销。
  •   

简单:在编译过程之后,每个泛型都是Object,它只是为你添加了转换,如果你做错了,它将产生编译错误。

关于unchecked注释,当编译器无法确定您正在做什么是正确的时(例如,您使用的原始类型与GenericBase<Object>

除了set类型之外,您有T方法发出的警告,但由于您使用的是原始类型,因此您不知道T是什么,并生成此警告让你知道你正在使用原始类型(坏事)。

您可以使用注释说:&#34;我知道它是原始类型,但我知道它是合法的,我知道我在做什么&#34;。

混合原始类型和泛型类型是可能的,因为泛型的实现方式,如上所述,在编译器处理后T变为Object,这意味着像{一样的原始对象{1}}与GenericBase相同。

它没有要求使用泛型进行任何转换的原因是因为它将为您添加转换(并且您可以确保代码将始终在运行时工作而不用担心可能{{1 }})。