我最近发现,数组在 Java 中被具体化了。也就是说,它们仅在运行时才知道类型信息。但我对这个定义有点困惑。
如果说数组仅在运行时知道类型信息,那么我应该能够将任何值分配给任何数组,因为类型仅在运行时才知道,并且错误只会在运行时引发。但实时情况并非如此。我们得到一个编译时错误。
那么有人可以阐明“这意味着什么 - 数组被具体化”?
我认为这意味着给定的代码行将引发异常:
String[] arrayOfStrings = new String[10];
Object[] arrayOfObjects = arrayOfStrings; // compiles fine
arrayOfObjects[0] = new Integer(2); // throws a runtime exception (ArrayStoreException IIRC)
数组是协变的:String[] 扩展 Object[]。但是数组的实际类型在运行时是已知的,并且尝试存储不正确类型的实例会引发异常。
我相信您正在寻找的术语是可具体化的。
可具体化的类型不会因为运行时的类型擦除而丢失任何类型信息。可具体化类型的示例包括:
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 (好)
如果说数组只在运行时知道类型信息,我应该能够将任何值分配给任何数组,因为只有在运行时才知道类型,错误只会在运行时抛出。但实时情况并非如此。我们得到一个编译时错误。
可重构类型在运行时和编译时知道它们的类型,这就是为什么编译器仍然会阻止你在可能的地方犯下愚蠢的错误(让它们通过有什么意义?)
但是,有时编译器不能总是确定赋值(例如)是否有效,因为它不知道确切的类型,而这是具体类型可以检查的地方。例如:
Object[] arr = new String[5];
arr[0] = 7;
...这将编译,因为在第二行编译器只知道数组的静态类型为Object
,而动态类型更具体。它将在运行时作为异常失败,它只能这样做,因为(与通用集合类不同)特定类型在运行时是已知的。
如文档中所述:
可具体化类型是其类型信息在运行时完全可用的类型。这包括原语、非泛型类型、原始类型和未绑定通配符的调用。
不可具体化类型是在编译时通过类型擦除删除信息的类型——调用未定义为无界通配符的泛型类型。一个不可具体化的类型在运行时没有它的所有信息可用。不可具体化类型的示例是 List 和 List;JVM 在运行时无法区分这些类型。如对泛型的限制中所示,在某些情况下不能使用不可具体化的类型:例如,在 instanceof 表达式中,或作为数组中的元素。
因此,数组是具体化和协变的,但泛型本质上是不变的和类型擦除的。ArrayStore
如果未添加正确类型的元素,数组提供运行时类型安全性并引发异常。