5.5 Initialization

Initialization of a class or interface consists of executing its class or interface initialization method (§2.9.2). A class or interface C may be initialized only as a result of:

  • The execution of any one of the Java Virtual Machine instructions new, getstatic, putstatic, or invokestatic that references C (§new, §getstatic, §putstatic, §invokestatic).

    Upon execution of a new instruction, the class to be initialized is the class referenced by the instruction.

    Upon execution of a getstatic, putstatic, or invokestatic instruction, the class or interface to be initialized is the class or interface that declares the resolved field or method.

  • The first invocation of a java.lang.invoke.MethodHandle instance which was the result of method handle resolution (§5.4.3.5) for a method handle of kind 2 (REF_getStatic), 4 (REF_putStatic), 6 (REF_invokeStatic), or 8 (REF_newInvokeSpecial).

    This implies that the class of a bootstrap method is initialized when the bootstrap method is invoked for an invokedynamic instruction (§invokedynamic), as part of the continuing resolution of the call site specifier.

  • Invocation of certain reflective methods in the class library (§2.12), for example, in class Class or in package java.lang.reflect.

  • If C is a class, the initialization of one of its subclasses.

  • If C is an interface that declares a non-abstract, non-static method, the initialization of a class that implements C directly or indirectly.

  • Its designation as the initial class or interface at Java Virtual Machine startup (§5.2). Prior to initialization, a class or interface must be linked, that is, verified, prepared, and optionally resolved. Because the Java Virtual Machine is multithreaded, initialization of a class or interface requires careful synchronization, since some other thread may be trying to initialize the same class or interface at the same time. There is also the possibility that initialization of a class or interface may be requested recursively as part of the initialization of that class or interface. The implementation of the Java Virtual Machine is responsible for taking care of synchronization and recursive initialization by using the following procedure. It assumes that the Class object has already been verified and prepared, and that the Class object contains state that indicates one of four situations:

  • This Class object is verified and prepared but not initialized.

  • This Class object is being initialized by some particular thread.

  • This Class object is fully initialized and ready for use.

  • This Class object is in an erroneous state, perhaps because initialization was attempted and failed. For each class or interface C, there is a unique initialization lock LC. The mapping from C to LC is left to the discretion of the Java Virtual Machine implementation. For example, LC could be the Class object for C, or the monitor associated with that Class object. The procedure for initializing C is then as follows:

    1. Synchronize on the initialization lock, LC, for C. This involves waiting until the current thread can acquire LC.

    2. If the Class object for C indicates that initialization is in progress for C by some other thread, then release LC and block the current thread until informed that the in-progress initialization has completed, at which time repeat this procedure.

      Thread interrupt status is unaffected by execution of the initialization procedure.

    3. If the Class object for C indicates that initialization is in progress for C by the current thread, then this must be a recursive request for initialization. Release LC and complete normally.

    4. If the Class object for C indicates that C has already been initialized, then no further action is required. Release LC and complete normally.

    5. If the Class object for C is in an erroneous state, then initialization is not possible. Release LC and throw a NoClassDefFoundError.

    6. Otherwise, record the fact that initialization of the Class object for C is in progress by the current thread, and release LC.

      Then, initialize each final static field of C with the constant value in its ConstantValue attribute (§4.7.2), in the order the fields appear in the ClassFile structure.

    7. Next, if C is a class rather than an interface, then let SC be its superclass and let SI1, …​, SIn be all superinterfaces of C (whether direct or indirect) that declare at least one non-abstract, non-static method. The order of superinterfaces is given by a recursive enumeration over the superinterface hierarchy of each interface directly implemented by C. For each interface I directly implemented by C (in the order of the interfaces array of C), the enumeration recurs on I’s superinterfaces (in the order of the interfaces array of I) before returning I.

      For each S in the list [ SC, SI1, …​, SIn ], if S has not yet been initialized, then recursively perform this entire procedure for S. If necessary, verify and prepare S first.

      If the initialization of S completes abruptly because of a thrown exception, then acquire LC, label the Class object for C as erroneous, notify all waiting threads, release LC, and complete abruptly, throwing the same exception that resulted from initializing SC.

    8. Next, determine whether assertions are enabled for C by querying its defining class loader.

    9. Next, execute the class or interface initialization method of C.

    10. If the execution of the class or interface initialization method completes normally, then acquire LC, label the Class object for C as fully initialized, notify all waiting threads, release LC, and complete this procedure normally.

    11. Otherwise, the class or interface initialization method must have completed abruptly by throwing some exception E. If the class of E is not Error or one of its subclasses, then create a new instance of the class ExceptionInInitializerError with E as the argument, and use this object in place of E in the following step. If a new instance of ExceptionInInitializerError cannot be created because an OutOfMemoryError occurs, then use an OutOfMemoryError object in place of E in the following step.

    12. Acquire LC, label the Class object for C as erroneous, notify all waiting threads, release LC, and complete this procedure abruptly with reason E or its replacement as determined in the previous step. A Java Virtual Machine implementation may optimize this procedure by eliding the lock acquisition in step 1 (and release in step 4/5) when it can determine that the initialization of the class has already completed, provided that, in terms of the Java memory model, all happens-before orderings (JLS §17.4.5) that would exist if the lock were acquired, still exist when the optimization is performed.

贡献翻译,请加 QQ: 840750575    点击这里给我发消息
数码
沪ICP备19006215号-4