122. Java 泛型 - 原始类型

0 阅读3分钟

122. Java 泛型 - 原始类型

1. 什么是原始类型?

原始类型是泛型类或接口的名称,而没有任何类型参数。例如,假设我们有一个泛型类 Box,它有一个类型参数 T

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

为了创建 Box<T> 的参数化类型,您需要为类型参数 T 提供一个实际的类型参数:

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

在这个例子中,Box<Integer> 是参数化类型,意味着 Box 被指定为存储 Integer 类型的数据。

原始类型

如果在声明 Box 时省略了类型参数,则它变成了原始类型。例如:

Box rawBox = new Box();

在这个例子中,Box 被称为泛型类型 Box<T> 的原始类型。注意,原始类型本身并不是泛型类或接口的类型,它只是泛型类名称的一个版本,尚未应用任何类型参数。

非泛型类和接口 并不是原始类型,只有泛型类或接口才有原始类型的概念。

原始类型的行为

当使用原始类型时,代码会表现出类似于泛型未引入之前的行为。举个例子,原始类型的 Box 会退化为 Object 类型,允许存储任何类型的数据,这也意味着你将失去类型安全的好处。

例如:

Box rawBox = new Box();          // 使用原始类型
Box<String> stringBox = new Box<>();
rawBox = stringBox;              // 允许这样做

在这段代码中,Box<String> 被赋值给原始类型的 rawBox,是允许的,因为原始类型在编译时不进行类型检查。

原始类型的警告

然而,问题出现在将原始类型分配给具体类型时,编译器会发出警告。比如:

Box rawBox = new Box();          // 原始类型 Box<T>
Box<Integer> intBox = rawBox;    // 警告: 未检查转换

这段代码的 rawBox 是一个原始类型,赋值给 Box<Integer> 时,编译器会发出警告:未检查的转换

如果尝试使用原始类型调用泛型方法,也会出现警告,例如:

Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8);  // 警告: 未检查的方法调用

在这段代码中,rawBox.set(8) 是一个未经检查的操作,编译器发出警告,表示您绕过了类型检查,可能导致类型不安全的问题。

因此,强烈建议避免使用原始类型。

2. 未选中的警告消息

当将旧代码与泛型代码混合时,可能会遇到类似以下的警告:

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

这种警告通常出现在混合使用原始类型和泛型类型时。例如:

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

    static Box createBox(){
        return new Box();  // 使用原始类型
    }
}

在这个示例中,createBox() 返回一个原始类型的 Box,并且赋值给了 Box<Integer> 类型的变量 bi,编译器无法确定类型安全性,因此给出了 unchecked 警告。

如何查看未选中的警告?

默认情况下,unchecked 警告是禁用的,编译器会提示“未选中的操作”。要查看所有未选中的警告,可以使用 -Xlint:unchecked 重新编译代码:

javac -Xlint:unchecked WarningDemo.java

这样会显示更详细的警告信息,例如:

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

如何禁用未选中的警告?

如果希望禁用所有未选中的警告,可以使用 -Xlint:-unchecked 标志:

javac -Xlint:-unchecked WarningDemo.java

如果您希望在代码中禁用特定的方法或类的警告,可以使用 @SuppressWarnings("unchecked") 注解:

@SuppressWarnings("unchecked")
public void someMethod() {
    // Some code that causes unchecked warnings
}

这会禁止显示“未选中的操作”的警告,但请注意,@SuppressWarnings 应谨慎使用,因为它可能掩盖潜在的类型安全问题。