Java:原始类型与泛型

标签 java arrays generics compiler-warnings

<分区>

考虑下面的示例代码

/* The new Java 5 or later Generic code */
class TestInserter {
    public static void main(String[] ar) {
        List<Integer> myList = new ArrayList<Integer>();
        myList.add(20);
        myList.add(42);
        Inserter ins = new Inserter();
        ins.insert(myList);
    }
}

/* Legacy Code */
class Inserter {
    public void insert(List list) {
        list.add(new Integer(55));
    }
}

编译和执行上面的代码会运行得很好,没有来自编译器或 JVM 的任何提示。 非类型安全 insert() 方法在我们的类型安全 ArrayList 中插入一个新的 Integer 对象。但是,如果我将插入方法更改为如下所示:

public void insert(List list) {
        list.add(new String("55"));
}

说什么?!上面的代码会运行吗?想一想,是的,它肯定会运行,这很奇怪,但是是的,上面的代码编译并运行得很好。 这与 Arrays 有点不同,Arrays 为您提供编译时和运行时保护,并防止此类事情发生。他们为什么这样做泛型?为什么 Java 允许泛型输入指定类型以外的值?!

最佳答案

现在是答案。使用 insert 方法将 Integer 添加到我们的列表中是非常安全和允许的,因为它与我们为 myList 变量指定的类型相匹配.但是,当我们尝试将一个 String 插入到一个只包含 Integer 值的 ArrayList 中时,就会出现问题,不是在编译时,而是在运行时,当您尝试在错误添加的 String 实例上调用特定于 Integer 的方法时。

为了理解整个问题及其目的,您应该了解一件事 - JVM 不知道您试图将 String 插入 ArrayList 意味着仅包含Integer您所有的泛型及其类型安全性都仅限于编译时。通过称为“类型删除”的过程,编译器从通用代码中删除所有类型参数。换句话说,即使你写了这样的东西:

List<Integer> myList = new ArrayList<>();

编译完成后变成如下:

List myList = new ArrayList();

但是,为什么他们要这样保留泛型呢?

答案很简单!如果不是因为这种奇怪的行为,那么早期 Java 版本的遗留代码就会被破坏,数百万 Java 开发人员将不得不编辑数万亿的旧 Java 代码以使其再次运行!

但是不要责怪编译器;当您尝试运行代码时,编译器会尝试向您发出以下警告:

$> javac TestInserter.java  
Note: TestInserter.java uses unchecked or unsafe operations.  
Note: Recompile with -Xlint:unchecked for details.

当您按照编译器的要求执行以下操作时:

$> javac -Xlint:unchecked TestInserter.java
TestInserter.java:15: warning: [unchecked] unchecked call to add(E) as a member of the raw type List  
        list.add(new String("55"));  
                 ^  
where E is a type-variable:  
  E extends Object declared in interface List  
1 warning    

就编译器而言,它试图告诉您它怀疑您程序中的某些代码可能最终会遇到麻烦。

总而言之,将泛型视为编译时保护。编译器使用类型信息(参数中指定的类型)来确保您不会将错误的内容插入到集合(或用户定义的泛型类型)中,并且您不会从错误的引用类型中获取值。 所有通用保护都是编译时的!就是这样。

关于Java:原始类型与泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42894976/

相关文章:

java - 如何在黑莓 SDK 中检查 Activity 的互联网连接?

java - 如何抑制Java对话框 "Unavailable Version of Java Requested"

java - 最终变量赋值 : at declaration or in constructor?

c - 数组中有符号和无符号字符的索引有什么区别?

c# - 根据索引获取数组项

c - _Generic 表达式的死分支导致编译器错误 (C11)

java - Selenium2 的 Select 对象不会在 IE8 中触发 onchange 事件

php - 从数组的数组中删除重复的数组

c# - Nullable<T> 作为参数

ios - Codable 对象的 Swift 4 集合