Raw Types

raw type(原生类型)是不带任何类型传参的泛型类或者接口。例如,下面这个Box泛型类:

public class Box<T> {
    public void set(T t) { /* ... */ }
    // ...
}

创建带参数的Box<T>类型,你需要为类型参数T提供实际的类型传参:

Box<Integer> intBox = new Box<>();

如果类型传参被省略,你就创建了一个Box<T>的原生类型:

Box rawBox = new Box();

也就是说,Box是泛型类型Box<T>的原生类型。但是,非泛型类或者接口类型不是原生类型。

原生类型在旧版本代码中,因为在JDK5.0之前许多API类(比如Collections类)。当使用原生类型时,你其实使用的是pre-generics行为-Box为你提供对象。为了向下兼容,可以将参数化的类型负值给它的原生类型:

Box<String> stringBox = new Box<>();
Box rawBox = stringBox;               // OK

但是如果我们将原生类型赋值给一个参数化类型,将会得到警告:

Box rawBox = new Box();           // rawBox is a raw type of Box<T>
Box<Integer> intBox = rawBox;     // warning: unchecked conversion

如果我们使用原生类型来调用在相应的泛型类型中定义的泛型方法,也会收到警告:

Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8);  // warning: unchecked invocation to set(T)

该警告表明原生类型会绕过泛型类型检查,从而导致不安全代码的捕获推迟到运行时。因此,我们应避免使用原生类型。

在后面的Type Erasure部分将会介绍更多的Java编译器如何使用原生类型的信息。

Unchecked Error Messages

就像上面提到的,当遗留代码和泛型代码混合在一起时,我们可能遇到如下的告警信息:

Note: Example.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

当我们使用操作原生类型的老旧API就会发生这种情况,以下面的代码为例:

public class WarningDemo {
    public static void main(String[] args){
        Box<Integer> bi;
        bi = createBox();
    }

    static Box createBox(){
        return new Box();
    }
}

unchecked这个术语的意思是编译器没有足够的类型信息来进行全类型检查从而确保类型安全。虽然编译器给出了提示,但是默认情况下unchecked警告是无效的。使用-Xlint:unchecked参数重新编译可以查看所有unchecked警告。

使用-Xlint:unchecked参数重新编译上面的例子会得到如下信息:

WarningDemo.java:4: warning: [unchecked] unchecked conversion
found   : Box
required: Box<java.lang.Integer>
        bi = createBox();
                      ^
1 warning

想要完全警用未检查警告,可以使用参数-Xlint:-unchecked。注解@SuppressWarnings("unchecked")阻止所有的未检查警告。如果对@SuppressWarnings语法不熟悉,参考Annotations章节的相关内容。

Last updated