我刚刚通读了 Java 虚拟机规范和 section on class loading让我很困惑。就我的一般理解和阅读规范后,我认为一个类的整体实例化由以下步骤组成,顺序如下:
ClassNotFoundException
被抛出。在这一点上,已经发生了一些基本的验证,其中 ClassFormatError
如果字节数组不代表 Java 类(例如,缺少魔数(Magic Number))或 UnsupportedClassVersionError
则抛出如果正在运行的 JVM 实例不支持类版本。 LinkageError
的子类被抛出。链接包括三个子步骤:VerifyError
被抛出。 OutOfMemoryError
。)IncompatibleClassChangeError
被抛出。如果找不到引用的类,则 NoClassDefFoundError
抛出基本上包裹了一个 ClassNotFoundException
由试图加载此引用类的类加载器引发的。如果被引用的类引用自身,则 ClassCircularityError
被抛出。解决方案可以以两种方式之一进行,这取决于 JVM 的实现者static
运行在类中定义为 Java 代码的初始化程序。如果异常是由这样的初始化程序引起的,则该异常将被重新抛出,并包装在 ExceptionInInitializerError
中。 . 令我困惑的是上述类加载机制的解析阶段。为什么解析被定义为链接中的一个明确步骤,特别是在准备之后发生?已经在description of the class loading phase内, 提到
If C has any direct superinterfaces, the symbolic references from C to its direct superinterfaces are resolved using the algorithm of §5.4.3.1.
由于验证是 described,所以在进行验证时是否也未解析符号引用:
Verification (§4.10) ensures that the binary representation of a class or interface is structurally correct (§4.9). Verification may cause additional classes and interfaces to be loaded (§5.3) but need not cause them to be verified or prepared.
我一直在脑海里想起这张照片
来源:http://www.programcreek.com
我几乎在任何解释类加载的地方都看到过。不应将解析视为整体责任,它是所有阶段、创建/加载、验证、链接和初始化的一部分(因为解析可以延迟完成)。
目前,我认为从该图像中取出分辨率阶段并将其声明为可以随时使用的通用过程是有意义的,因为在任何阶段可能需要有关其他类的信息,以便加载此类class 是必需的,当然也需要解析对此类的符号引用。从显示的图片来看,解决方案似乎只发生在一系列单独事件中的特定点。
我怀疑这种对分辨率的描述是一个专门的步骤,可能只是那个时代的遗产,在这个时代,分辨率从来没有被懒惰地进行过,而是在所有剩余的符号引用都得到了解决的地方。
我想知道的 :今天的 JVM 中的解析应该按照我描述的方式来理解吗?还是我错了,分辨率仍然可以理解为固定时间线中的专用步骤,就像图像显示的那样?
最佳答案
您的图片显示在准备后总是出现解析,但这不起作用。需要直接父类(super class)进行准备,因为您需要了解父类(super class)的实例字段以确定特定类的对象实例内存布局。此外,在使用类之前,即在创建实例或调用静态方法之前,必须执行类及其父类(super class)的静态初始化程序。
这与所有其他引用类型的解析不同,后者可以延迟更长时间。允许在第一次调用方法之前解析方法中使用的类型。
当你看第一章5.4.3. Resolution ,有明确说明:
The Java Virtual Machine instructions anewarray, checkcast, getfield, getstatic, instanceof, invokedynamic, invokeinterface, invokespecial, invokestatic, invokevirtual, ldc, ldc_w, multianewarray, new, putfield, and putstatic make symbolic references to the run-time constant pool. Execution of any of these instructions requires resolution of its symbolic reference.
所以区别就很明显了。有直接父类(super class)的解析和直接实现的接口(interface)(或在接口(interface)的情况下的超接口(interface))的解析,并且存在用于上述字节码指令的符号引用的解析可以推迟。
关于java - Java 类加载的解析阶段实际上从哪里开始?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20347074/