java - 意外地将字符串添加到 List<Integers>

标签 java generics collections polymorphism raw-types

我不明白编译器在输出 Test 时如何处理下面的代码,而我预计会出现错误。

List<Integer> b = new ArrayList<Integer>();
List a = b;
a.add("test");
System.out.println(b.get(0));

我希望有人能告诉我编译器在执行代码时所经历的确切步骤,以便我能够理解输出。我目前的理解是:

  1. 编译器会在编译期间检查 List 类中是否存在支持参数类型的 add 方法,该类的原始类型是 add(Object e)
  2. 但是,在运行时,它会尝试从实际对象 List 调用 add(Object e) ,因为实际对象不是原始类型,而是持有此方法add(Integer e) 方法。

如果在实际对象 List 中没有 add(Object e) 方法,它如何仍然以某种方式将字符串添加到整数列表中?

最佳答案

你很接近。编译时间检查所有结果:

a类型为 List所以调用

a.add("test");

成功了。 b是(编译时)类型 ArrayList<Integer>所以

b.get(0)

也 checkout 。请注意,检查仅针对变量的编译时类型。当编译器看到 a.add("test")知道变量 a 引用的对象的运行时值.一般来说,它确实不能(理论计算机科学对此有一个结果),尽管控制流类型分析可以捕获许多这样的东西。像 TypeScript 这样的语言可以在编译时做出惊人的事情。

现在您可能会假设在运行时可以检查这些事情。 las,在 Java 中他们不能。 Java 删除泛型类型。查找有关 Java 类型删除的文章以了解详细信息。 TL;DR 是一个 List<Integer>在编译时变为原始 List在运行时。 JVM 没有办法“具体化”泛型(尽管其他语言可以!)所以当引入泛型时,Java 决定只删除泛型类型。所以在运行时,你的代码没有类型问题。

让我们看一下编译后的代码:

   0: new           #2                  // class java/util/ArrayList
   3: dup
   4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
   7: astore_1
   8: aload_1
   9: astore_2
  10: aload_2
  11: ldc           #4                  // String test
  13: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
  18: pop
  19: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
  22: aload_1
  23: iconst_0
  24: invokeinterface #7,  2            // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
  29: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
  32: return

这里可以直接看到没有运行时类型检查。因此,对您的问题的完整(但看似轻率)的回答是,Java 仅在编译时根据变量(在编译时已知)的类型检查类型,但泛型类型参数被删除并代码在没有它们的情况下运行。

关于java - 意外地将字符串添加到 List<Integers>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52681096/

相关文章:

java - 如何跨防火墙解析网页

java - gradle:切换到实现/测试实现在访问配置时导致错误

参数化类 : Unbounded Wildcards vs Raw Type 的 Java 泛型

scala - 更新作为可变集合的可变 HashMap 值

java - 使用 Checkstyles 防止准备好的语句泄漏

java - 什么是 "continue"关键字,它在 Java 中是如何工作的?

java - Java 泛型何时在运行时使用转换?

java - 分层HashMap N阶HMM实现

java - 高效地多次迭代 map

java - 如何在 Java 中将 int[] 转换为 List<Integer>?