1

今天编译这段代码时我很惊讶:

class GenericClass<T> {
    public void emptyMethod(T instance) {
        // ..
    }

    public void print(T instance) {
        System.out.println(instance);
    }
}

public class Main {

    public static void main(String[] args) {
        GenericClass first = new GenericClass();
        System.out.println("Wow");
        first.emptyMethod(10);
        first.print(16);
    }

}

编译器发出警告(类型安全:方法 emptyMethod(Object) 属于原始类型 GenericList。应该参数化对泛型类型 GenericList 的引用),但无论如何它不会导致编译器错误并且它运行“正常”(至少提供的打印方法)。据我了解,编译器使用 object 作为类型参数,但我发现它违反直觉。为什么编译器会做这样的事情?为什么不需要我指定类型参数?

4

2 回答 2

7

基本上,您使用的是原始类。

回想一下泛型在 Java 中首次引入的时候:有大量代码已经使用过ListArrayList等等。为了避免破坏所有代码,但仍然重用现有的类,引入了原始类型——它基本上是使用泛型输入好像它不是一个。

如您所见,您会收到警告-因此值得避免-但这是完全允许它的主要原因。

有关更多信息,请参阅JLS 的第 4.8 节,其中包括:

原始类型与通配符密切相关。两者都基于存在类型。原始类型可以被认为是通配符,其类型规则故意不合理,以适应与遗留代码的交互。从历史上看,原始类型在通配符之前;它们首先在 GJ 中被介绍,并在 Gilad Bracha、Martin Odersky、David Stoutamire 和 Philip Wadler 的论文让未来安全:为 Java 编程语言添加通用性,在 ACM 对象会议论文集中进行了描述-面向编程、系统、语言和应用程序 (OOPSLA 98),1998 年 10 月。

于 2013-02-07T19:57:44.877 回答
2

你必须知道泛型是如何在 Java 中实现的。它们远非完美。您必须记住,在运行时一切都是对象。运行时没有类型。

添加了泛型以在您需要的地方增加安全性,但如果您不想使用它,您可以忽略警告并使用未参数化的实例。

但是,如果您希望 java 编译器帮助您实现类型安全,那么您可以对泛型类实例进行参数化。例如,一旦您创建了 GenericClass,编译器将不允许您将其与整数参数一起使用(first.emptyMethod(10) 将无法编译)。如果您进行显式类型转换,您仍然可以使用整数参数。

因此,将其视为增加安全性的良好做法,仅当您遵守规则时才有效。

于 2013-02-07T19:58:33.510 回答