8

我最近发现,数组在 Java 中被具体化了。也就是说,它们仅在运行时才知道类型信息。但我对这个定义有点困惑。

如果说数组仅在运行时知道类型信息,那么我应该能够将任何值分配给任何数组,因为类型仅在运行时才知道,并且错误只会在运行时引发。但实时情况并非如此。我们得到一个编译时错误。

那么有人可以阐明“这意味着什么 - 数组被具体化”?

4

4 回答 4

9

我认为这意味着给定的代码行将引发异常:

String[] arrayOfStrings = new String[10];
Object[] arrayOfObjects = arrayOfStrings; // compiles fine
arrayOfObjects[0] = new Integer(2); // throws a runtime exception (ArrayStoreException IIRC)

数组是协变的:String[] 扩展 Object[]。但是数组的实际类型在运行时是已知的,并且尝试存储不正确类型的实例会引发异常。

于 2013-05-13T09:23:21.687 回答
6

我相信您正在寻找的术语是可具体化的。

可具体化的类型不会因为运行时的类型擦除而丢失任何类型信息。可具体化类型的示例包括:

  • 原语
  • 非泛型引用类型
  • 数组或原语或非泛型引用类型的数组。

Reifiable 并不意味着在编译时不知道类型。这确实意味着无法键入以下内容:

List<Integer>[] myList;

数组携带有关它们存储的类型的运行时信息。Non-refiable 类型不能在运行时进行类型检查,这不会使它们成为数组组件类型的良好候选者。

当使用可具体化类型作为数组的组件类型时,例如String[]完整的类型信息在运行时可用,因此可以执行类型检查。

String[] someArray = new String[2];
//some factory returns Integer upcasted to Object
someArray[0] = someFactory.getType("Integer");  //throws RuntimeException

资料来源:

http://docs.oracle.com/javase/tutorial/java/generics/nonReifiableVarargsType.html http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#FAQ106 (好)

于 2013-05-13T09:31:15.580 回答
3

如果说数组只在运行时知道类型信息,我应该能够将任何值分配给任何数组,因为只有在运行时才知道类型,错误只会在运行时抛出。但实时情况并非如此。我们得到一个编译时错误。

可重构类型在运行时编译时知道它们的类型,这就是为什么编译器仍然会阻止你在可能的地方犯下愚蠢的错误(让它们通过有什么意义?)

但是,有时编译器不能总是确定赋值(例如)是否有效,因为它不知道确切的类型,而这是具体类型可以检查的地方。例如:

Object[] arr = new String[5];
arr[0] = 7;

...这将编译,因为在第二行编译器只知道数组的静态类型为Object,而动态类型更具体。它将在运行时作为异常失败,它只能这样做,因为(与通用集合类不同)特定类型在运行时是已知的。

于 2013-05-13T09:51:44.527 回答
1

文档中所述:

可具体化类型是其类型信息在运行时完全可用的类型。这包括原语、非泛型类型、原始类型和未绑定通配符的调用。

不可具体化类型是在编译时通过类型擦除删除信息的类型——调用未定义为无界通配符的泛型类型。一个不可具体化的类型在运行时没有它的所有信息可用。不可具体化类型的示例是 List 和 List;JVM 在运行时无法区分这些类型。如对泛型的限制中所示,在某些情况下不能使用不可具体化的类型:例如,在 instanceof 表达式中,或作为数组中的元素。

因此,数组是具体化和协变的,但泛型本质上是不变的和类型擦除的。ArrayStore如果未添加正确类型的元素,数组提供运行时类型安全性并引发异常。

于 2015-10-20T08:31:20.340 回答