This specification is not final and is subject to change. Use is subject to license terms.

Sealed Classes

Changes to the Java® Virtual Machine Specification • Version 16-internal+0-adhoc.gbierman.20201104

This document describes changes to the Java Virtual Machine Specification to support sealed classes and interfaces, a preview feature of Java SE 16. A sealed class or interface restricts extension and implementation to an enumerated set of authorized subclasses or subinterfaces. See the JEP for an overview of the feature.

Section 4.7 specifies a new PermittedSubclasses attribute.

Section 5.3.5 specifies the checks performed at class derivation time in order to enforce the PermittedSubclasses attribute.

A number of revisions to 5.3 are also included in order to more accurately specify how the new class creation checks interact with the existing behavior of the reference implementation.

Changes are described with respect to existing sections of the JVM Specification. New text is indicated like this and deleted text is indicated like this. Explanation and discussion, as needed, is set aside in grey boxes.

Chapter 4: The class File Format

4.7 Attributes

Attributes are used in the ClassFile, field_info, method_info, and Code_attribute structures of the class file format (4.1, 4.5, 4.6, 4.7.3).

All attributes have the following general format:

attribute_info {
    u2 attribute_name_index;
    u4 attribute_length;
    u1 info[attribute_length];
}

For all attributes, the attribute_name_index item must be a valid unsigned 16-bit index into the constant pool of the class. The constant_pool entry at attribute_name_index must be a CONSTANT_Utf8_info structure (4.4.7) representing the name of the attribute. The value of the attribute_length item indicates the length of the subsequent information in bytes. The length does not include the initial six bytes that contain the attribute_name_index and attribute_length items.

28 29 attributes are predefined by this specification. They are listed three times, for ease of navigation:

Within the context of their use in this specification, that is, in the attributes tables of the class file structures in which they appear, the names of these predefined attributes are reserved.

Any conditions on the presence of a predefined attribute in an attributes table are specified explicitly in the section which describes the attribute. If no conditions are specified, then the attribute may appear any number of times in an attributes table.

The predefined attributes are categorized into three groups according to their purpose:

  1. Six Seven attributes are critical to correct interpretation of the class file by the Java Virtual Machine:

    • ConstantValue
    • Code
    • StackMapTable
    • BootstrapMethods
    • NestHost
    • NestMembers
    • PermittedSubclasses

    In a class file whose version number is v, each of these attributes must be recognized and correctly read by an implementation of the Java Virtual Machine if the implementation supports version v of the class file format, and the attribute was first defined in version v or earlier of the class file format, and the attribute appears in a location where it is defined to appear.

  2. Nine attributes are not critical to correct interpretation of the class file by the Java Virtual Machine, but are either critical to correct interpretation of the class file by the class libraries of the Java SE Platform, or are useful for tools (in which case the section that specifies an attribute describes it as "optional"):

    • Exceptions
    • InnerClasses
    • EnclosingMethod
    • Synthetic
    • Signature
    • SourceFile
    • LineNumberTable
    • LocalVariableTable
    • LocalVariableTypeTable

    In a class file whose version number is v, each of these attributes must be recognized and correctly read by an implementation of the Java Virtual Machine if the implementation supports version v of the class file format, and the attribute was first defined in version v or earlier of the class file format, and the attribute appears in a location where it is defined to appear.

  3. Thirteen attributes are not critical to correct interpretation of the class file by the Java Virtual Machine, but contain metadata about the class file that is either exposed by the class libraries of the Java SE Platform, or made available by tools (in which case the section that specifies an attribute describes it as "optional"):

    • SourceDebugExtension
    • Deprecated
    • RuntimeVisibleAnnotations
    • RuntimeInvisibleAnnotations
    • RuntimeVisibleParameterAnnotations
    • RuntimeInvisibleParameterAnnotations
    • RuntimeVisibleTypeAnnotations
    • RuntimeInvisibleTypeAnnotations
    • AnnotationDefault
    • MethodParameters
    • Module
    • ModulePackages
    • ModuleMainClass

    An implementation of the Java Virtual Machine may use the information that these attributes contain, or otherwise must silently ignore these attributes.

Table 4.7-A. Predefined class file attributes (by section)

Attribute Section class file Java SE
ConstantValue 4.7.2 45.3 1.0.2
Code 4.7.3 45.3 1.0.2
StackMapTable 4.7.4 50.0 6
Exceptions 4.7.5 45.3 1.0.2
InnerClasses 4.7.6 45.3 1.1
EnclosingMethod 4.7.7 49.0 5.0
Synthetic 4.7.8 45.3 1.1
Signature 4.7.9 49.0 5.0
SourceFile 4.7.10 45.3 1.0.2
SourceDebugExtension 4.7.11 49.0 5.0
LineNumberTable 4.7.12 45.3 1.0.2
LocalVariableTable 4.7.13 45.3 1.0.2
LocalVariableTypeTable 4.7.14 49.0 5.0
Deprecated 4.7.15 45.3 1.1
RuntimeVisibleAnnotations 4.7.16 49.0 5.0
RuntimeInvisibleAnnotations 4.7.17 49.0 5.0
RuntimeVisibleParameterAnnotations 4.7.18 49.0 5.0
RuntimeInvisibleParameterAnnotations 4.7.19 49.0 5.0
RuntimeVisibleTypeAnnotations 4.7.20 52.0 8
RuntimeInvisibleTypeAnnotations 4.7.21 52.0 8
AnnotationDefault 4.7.22 49.0 5.0
BootstrapMethods 4.7.23 51.0 7
MethodParameters 4.7.24 52.0 8
Module 4.7.25 53.0 9
ModulePackages 4.7.26 53.0 9
ModuleMainClass 4.7.27 53.0 9
NestHost 4.7.28 55.0 11
NestMembers 4.7.29 55.0 11
PermittedSubclasses 4.7.30 60.65535 16

Table 4.7-B. Predefined class file attributes (by class file format)

Attribute class file Java SE Section
ConstantValue 45.3 1.0.2 4.7.2
Code 45.3 1.0.2 4.7.3
Exceptions 45.3 1.0.2 4.7.5
SourceFile 45.3 1.0.2 4.7.10
LineNumberTable 45.3 1.0.2 4.7.12
LocalVariableTable 45.3 1.0.2 4.7.13
InnerClasses 45.3 1.1 4.7.6
Synthetic 45.3 1.1 4.7.8
Deprecated 45.3 1.1 4.7.15
EnclosingMethod 49.0 5.0 4.7.7
Signature 49.0 5.0 4.7.9
SourceDebugExtension 49.0 5.0 4.7.11
LocalVariableTypeTable 49.0 5.0 4.7.14
RuntimeVisibleAnnotations 49.0 5.0 4.7.16
RuntimeInvisibleAnnotations 49.0 5.0 4.7.17
RuntimeVisibleParameterAnnotations 49.0 5.0 4.7.18
RuntimeInvisibleParameterAnnotations 49.0 5.0 4.7.19
AnnotationDefault 49.0 5.0 4.7.22
StackMapTable 50.0 6 4.7.4
BootstrapMethods 51.0 7 4.7.23
RuntimeVisibleTypeAnnotations 52.0 8 4.7.20
RuntimeInvisibleTypeAnnotations 52.0 8 4.7.21
MethodParameters 52.0 8 4.7.24
Module 53.0 9 4.7.25
ModulePackages 53.0 9 4.7.26
ModuleMainClass 53.0 9 4.7.27
NestHost 55.0 11 4.7.28
NestMembers 55.0 11 4.7.29
PermittedSubclasses 60.65535 16 4.7.30

Table 4.7-C. Predefined class file attributes (by location)

Attribute Location class file
SourceFile ClassFile 45.3
InnerClasses ClassFile 45.3
EnclosingMethod ClassFile 49.0
SourceDebugExtension ClassFile 49.0
BootstrapMethods ClassFile 51.0
Module, ModulePackages, ModuleMainClass ClassFile 53.0
NestHost, NestMembers ClassFile 55.0
PermittedSubclasses ClassFile 60.65535
ConstantValue field_info 45.3
Code method_info 45.3
Exceptions method_info 45.3
RuntimeVisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations method_info 49.0
AnnotationDefault method_info 49.0
MethodParameters method_info 52.0
Synthetic ClassFile, field_info, method_info 45.3
Deprecated ClassFile, field_info, method_info 45.3
Signature ClassFile, field_info, method_info 49.0
RuntimeVisibleAnnotations, RuntimeInvisibleAnnotations ClassFile, field_info, method_info 49.0
LineNumberTable Code 45.3
LocalVariableTable Code 45.3
LocalVariableTypeTable Code 49.0
StackMapTable Code 50.0
RuntimeVisibleTypeAnnotations, RuntimeInvisibleTypeAnnotations ClassFile, field_info, method_info, Code 52.0

4.7.30 The PermittedSubclasses Attribute

The PermittedSubclasses attribute is a variable-length attribute in the attributes table of a ClassFile structure. If a class or interface has a PermittedSubclasses attribute, any class or interface that attempts to extend or implement it must be named by the attribute (5.3.5).

In the Java Programming Language, there is a sealed modifier to indicate a class or interface that constrains extension in this way. In the class file, there is no ACC_SEALED flag. Instead, a sealed class or interface is indicated by the presence of the PermittedSubclasses attribute.

There may be at most one PermittedSubclasses attribute in the attributes table of a ClassFile structure whose ACC_FINAL flag is not set (4.1). If the ACC_FINAL flag is set, then the ClassFile structure must not have a PermittedSubclasses attribute.

We treat sealed as distinct from final—a sealed class has an enumerated list of designated subclasses, while a final class has no subclasses. Thus, a ClassFile structure may have a PermittedSubclasses attribute, or may have its ACC_FINAL flag set, but not both.

Alternatively, we could have let the PermittedSubclasses attribute refine the ACC_FINAL flag—reinterpreting "final" to mean "can't be extended, except for authorized subclasses". But doing so risks disrupting consumers of class files that have long assumed "final" means "has 0 subclasses" and that interfaces cannot be final.

The PermittedSubclasses attribute has the following format:

PermittedSubclasses_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 number_of_classes;
    u2 classes[number_of_classes];
}

The items of the PermittedSubclasses_attribute structure are as follows:

attribute_name_index

The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (4.4.7) representing the string "PermittedSubclasses".

attribute_length

The value of the attribute_length item indicates the length of the attribute, excluding the initial six bytes.

number_of_classes

The value of the number_of_classes item indicates the number of entries in the classes array.

classes[]

Each value in the classes array must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Class_info structure (4.4.1) representing a class or interface which is authorized to extend or implement the current class or interface.

The classes array is consulted when a class or interface that attempts to directly extend or implement the current class or interface is created (5.3.5). Array items that do not attempt to directly extend or implement the current class or interface are ignored.

Chapter 5: Loading, Linking, and Initializing

5.3 Creation and Loading

Creation of a class or interface C denoted by the name N consists of locating a binary representation the class or interface (4) and then deriving construction in the method area of the Java Virtual Machine (2.5.4) of an implementation-specific internal representation of C in the method area of the Java Virtual Machine (2.5.4).

Class or interface creation is triggered by another class or interface D, which references C through its run-time constant pool. Class or interface creation may also be triggered by D invoking methods in certain Java SE Platform class libraries (2.12) such as reflection.

When class or interface creation is triggered by a reference to C from a run-time constant pool, the process described in this section is followed. Class or interface creation triggered by a method of the Java SE Platform class libraries follows a similar process, the details of which are specified by the method.

If C is not an array class, it is created by loading a binary representation of C (4) created by loading it using a class loader. Array classes do not have an external binary representation; they are created by the Java Virtual Machine rather than by a class loader.

There are two kinds of class loaders: the bootstrap class loader supplied by the Java Virtual Machine, and user-defined class loaders. Every user-defined class loader is an instance of a subclass of the abstract class ClassLoader. Applications employ user-defined class loaders in order to extend the manner in which the Java Virtual Machine dynamically loads and thereby creates classes. User-defined class loaders can be used to create classes that originate from user-defined sources. For example, a class could be downloaded across a network, generated on the fly, or extracted from an encrypted file.

User-defined class loaders can be used to create classes that originate from user-defined sources. For example, a class could be downloaded across a network, generated on the fly, or extracted from an encrypted file.

A class loader L may create load C by defining defining it directly or by delegating to another class loader. If L creates defines C directly, we say that L defines C or, equivalently, that L is the defining loader of C.

When one class loader delegates to another class loader, the loader that initiates the loading is not necessarily the same loader that completes the loading and defines the class. If L creates loads C, either by defining it directly or by delegation, we say that L initiates loading of C or, equivalently, that L is an initiating loader of C.

At run time, a class or interface is determined not by its name alone, but by a pair: its binary name (4.2.1) and its defining class loader. Each such class or interface belongs to a single run-time package. The run-time package of a class or interface is determined by the package name and defining class loader of the class or interface.

The Java Virtual Machine uses one of three procedures to create class or interface C denoted by N:

If an error occurs during class loading while the Java Virtual Machine is attempting to create a class, then an instance of a subclass of LinkageError must be thrown at a point in the program that (directly or indirectly) uses the class or interface being loaded.

If the Java Virtual Machine ever attempts to load a class C during verification (5.4.1) or resolution (5.4.3) (but not initialization (5.5)), and the class loader that is used to initiate loading of C throws an instance of ClassNotFoundException, then the Java Virtual Machine must throw an instance of NoClassDefFoundError whose cause is the instance of ClassNotFoundException.

This discussion appears to be a roundabout way to say "when you load a class via reflection, you get direct access to the exceptions that the reflection API throws". But those details can be left to the reflection API specification. For our purposes, this section is only concerned with the behavior of the JVM as it loads classes.

The details about wrapping ClassNotFoundException in NoClassDefFoundError are moved to sections 5.3.1 and 5.3.2, below.

(A subtlety here is that recursive class loading to load superclasses is performed as part of resolution (5.3.5, step 3). Therefore, a ClassNotFoundException that results from a class loader failing to load a superclass must be wrapped in a NoClassDefFoundError.)

Discussions about recursion are best left to 5.3.5.

A well-behaved class loader should maintain three properties:

We will sometimes represent a class or interface using the notation <N, Ld>, where N denotes the name of the class or interface and Ld denotes the defining loader of the class or interface.

We will also represent a class or interface using the notation NLi, where N denotes the name of the class or interface and Li denotes an initiating loader of the class or interface.

5.3.1 Loading Creation Using the Bootstrap Class Loader

The following steps are used to load and thereby create the nonarray class or interface C denoted by N using the bootstrap class loader.

First, the Java Virtual Machine determines whether the bootstrap class loader has already been recorded as an initiating loader of a class or interface denoted by N. If so, this class or interface is C, and no class creation is necessary.

Otherwise, the Java Virtual Machine passes the argument N to an invocation of a method on the bootstrap class loader to search load C. This will involve searching for a purported representation of C in a platform-dependent manner and then deriving C from that representation using the algorithm found in 5.3.5. Typically, a class or interface will be represented using a file in a hierarchical file system, and the name of the class or interface will be encoded in the pathname of the file.

Note that there is no guarantee that a purported representation found is valid or is a representation of C. This phase of loading must detect the following error:

Then the Java Virtual Machine attempts to derive a class denoted by N using the bootstrap class loader from the purported representation using the algorithm found in 5.3.5. That class is C.

If no purported representation of C is found, the bootstrap class loader throws an instance of ClassNotFoundException. Creation of C then fails with a NoClassDefFoundError whose cause is the ClassNotFoundException produced by the bootstrap class loader.

If deriving C from the purported representation fails, any of the errors specified in 5.3.5 may be thrown by the bootstrap class loader. Creation of C fails for the same reason.

It's confusing to treat class derivation as a followup step. While no particular API is specified to be used, the loadClass model matches what readers will expect. In that case, once the loadClass method returns, the class has already been derived and the creation process is complete (except that the Java Virtual Machine may need to wrap a ClassNotFoundException).

5.3.2 Loading Creation Using a User-defined Class Loader

The following steps are used to load and thereby create the nonarray class or interface C denoted by N using a user-defined class loader L.

First, the Java Virtual Machine determines whether L has already been recorded as an initiating loader of a class or interface denoted by N. If so, this class or interface is C, and no class creation is necessary.

Otherwise, the Java Virtual Machine invokes loadClass(N) on L. The value returned by the invocation is the created class or interface C. The Java Virtual Machine then records that L is an initiating loader of C (5.3.4). The remainder of this section describes this process in more detail.

When the loadClass method of the class loader L is invoked with the name N of a class or interface C to be loaded, L must perform one of the following two operations in order to load C:

  1. The class loader L can create an array of bytes representing C as the bytes of a ClassFile structure (4.1); it then must invoke the method defineClass of class ClassLoader. Invoking defineClass causes the Java Virtual Machine to derive a class or interface denoted by N using L from the array of bytes using the algorithm found in 5.3.5.

    If deriving C from the purported representation fails, any of the errors specified in 5.3.5 may be thrown by loadClass. Creation of C fails for the same reason.

    If the class or interface produced by loadClass has name N but is different than the class or interface derived by defineClass, creation fails and the Java Virtual Machine throws an instance of LinkageError or a subclass of LinkageError.

  2. The class loader L can delegate the loading of C to some other class loader L'. This is accomplished by passing the argument N directly or indirectly to an invocation of a method on L' (typically the loadClass method). The result of the invocation is C.

In either (1) or (2), if the class loader L is unable to load a class or interface denoted by N for any reason, it must throw an instance of ClassNotFoundException. Creation of C then fails with a NoClassDefFoundError whose cause is the ClassNotFoundException produced by the bootstrap class loader.

If the result of the loadClass invocation is null, or is a loaded class or interface with a name other than N, creation fails with a NoClassDefFoundError.

These additional rules attempt to capture actual error checks as observed in JDK 14 and OpenJ9 0.15.

The check in step 1 produces different errors in the two implementations: Hotspot throws a LinkageError, while J9 throws a NoClassDefFoundError.

Note that if defineClass is called by some loader other than the initiating loader, the check in step (1) is not performed. This is because the delegated loading is a reflective call, and so not subject to these JVM-level loading checks.

To do: what happens if the class loader throws an unexpected exception?

Since JDK 1.1, Oracle’s Java Virtual Machine implementation has invoked the loadClass method of a class loader in order to cause it to load a class or interface. The argument to loadClass is the name of the class or interface to be loaded. There is also a two-argument version of the loadClass method, where the second argument is a boolean that indicates whether the class or interface is to be linked or not. Only the two-argument version was supplied in JDK 1.0.2, and Oracle’s Java Virtual Machine implementation relied on it to link the loaded class or interface. From JDK 1.1 onward, Oracle’s Java Virtual Machine implementation links the class or interface directly, without relying on the class loader.

5.3.5 Deriving a Class from a class File Representation

The derivation process described here is an important, tightly-specified subprocess of loading and creation. These revisions make more prominent use of the term.

Steps 3 and 4 of the process include new checks to enforce the PermittedSubclasses attribute.

The following steps are used to derive a Class object for the nonarray class or interface C denoted by N using loader L from a purported representation in class file format.

This section says nothing about Class objects, which are only auxiliary to creation and loading. Instead, these rules describe how to derive an abstract "class or interface" from a name, class loader, and byte array.

  1. First, the Java Virtual Machine determines whether it has already recorded that L is an initiating loader of a class or interface denoted by N. If so, this creation attempt is invalid and loading throws a LinkageError. the attempt to derive a class or interface named N for class loader L is invalid. If so, derivation throws a LinkageError.

    An attempt to derive a class or interface named N for class loader L is invalid if one of the following are true:

    • L has already been recorded as as an initiating loader of a class or interface named N.

    • L is not the bootstrap class loader (5.3) and N is the reserved name java/lang/Object.

    The second case, combined with restrictions in 4.1, ensures that there is only one root of the class hierarchy, and the name java/lang/Object can reliably be used to refer to it.

    The Java SE API enforces additional security restrictions that prevent unauthorized attempts to load classes in certain packages, including java.*.

    In practice, the security restrictions make it impossible to test the Object rule—a SecurityException will happen before the JVM can perform this check. But for internal consistency, it seems important to state.

  2. Otherwise, the Java Virtual Machine attempts to parse the purported representation. However, the purported representation may not in fact be a valid representation of C.

    This phase of loading derivation must detect the following errors:

    • If the purported representation is not a ClassFile structure (4.1, 4.8), loading throws an instance of ClassFormatError.

      It doesn't make sense to try to parse a class file before determining that the version number is supported. The version check has to happen first.

    • Otherwise, if If the purported representation is not of a supported major or minor version (4.1) provides a major and minor version number in its 5th through 8th bytes (4.1), but the version number is not supported by this Java Virtual Machine implementation, loading derivation throws an instance of UnsupportedClassVersionError.

      UnsupportedClassVersionError, a subclass of ClassFormatError, was introduced to enable easy identification of a ClassFormatError caused by an attempt to load a class whose representation uses an unsupported version of the class file format. In JDK 1.1 and earlier, an instance of NoClassDefFoundError or ClassFormatError was thrown in case of an unsupported version, depending on whether the class was being loaded by the system class loader or a user-defined class loader.

    • Otherwise, if the purported representation is not a ClassFile structure (4.1, 4.8), derivation throws an instance of ClassFormatError.

    • Otherwise, if the purported representation does not actually represent a class or interface named N, loading derivation throws an instance of NoClassDefFoundError or an instance of one of its subclasses.

      This occurs when the purported representation has either a this_class item which specifies a name other than N, or an access_flags item which has the ACC_MODULE flag set.

  3. If C has a direct superclass, the symbolic reference from C to its direct superclass is resolved using the algorithm of 5.4.3.1. Note that if C is an interface it must have Object as its direct superclass, which must already have been loaded. Only Object has no direct superclass.

    Per 5.2, an arbitrary initial class or interface is the first to be created. If the initial class or interface is an interface, deriving it will recursively prompt the creation of (not-yet-loaded) Object here.

    Any exceptions that can be thrown due to class or interface resolution can be thrown as a result of this phase of loading derivation. In addition, this phase of loading derivation must detect the following errors:

    • If the class or interface named as the direct superclass of C is in fact an interface, loading throws an IncompatibleClassChangeError.

    • Otherwise, if any of the superclasses of C is C itself If the attempt to resolve the direct superclass leads to the current thread attempting to recursively derive a class named N using loader L, loading derivation throws a ClassCircularityError.

      How can we decide whether a superclass is "C itself" without actually creating the superclass first? And, of course, we can't create the superclass without recursively applying this check. This dependency loop is broken by detecting when a second attempt is made to derive a class named N.

    • Otherwise, if the class or interface named as the direct superclass of C is an interface or a final class, derivation throws a VerifyError.

      This check has long been specified as part of verification (4.10, 4.10.1). However, JDK 14 and OpenJ9 both perform it as part of class derivation.

      A VerifyError at this stage is out of place, but that's the exception that actually gets thrown. See JDK-8243582.

    • Otherwise, if the class named as the direct superclass of C has a PermittedSubclasses attribute (4.7.30) and any of the following are true, derivation fails with a IncompatibleClassChangeError:

      • The superclass belongs to a different run-time module than C.

      • C does not have its ACC_PUBLIC flag set (4.1) and the superclass belongs to a different run-time package than C.

      • No entry in the classes table of the superclass's PermittedSubclasses attribute references a class or interface with name N.

    These restrictions guarantee that an entry in PermittedSubclasses of the superclass will resolve to C. (We don't actually resolve the reference to C, because doing so would prompt a circularity, since derivation of C hasn't yet completed.)

    The Java language has an additional requirement that, if the classes belong to an unnamed module, they must both be in the same package. This encourages programmers to use the feature appropriately (they shouldn't try to spread a sealed hierarchy across different maintenance domains), but is not the sort of fundamental restriction the JVM needs to enforce. So another language or bytecode generator is free not to follow the package restriction.

    • Otherwise, if C is a class and some non-static method declared in C can override (5.4.5) a final, non-static method declared in a superclass of C, derivation throws a VerifyError.

      Same comment about the VerifyError.

  4. 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.

    Any exceptions that can be thrown due to class or interface resolution can be thrown as a result of this phase of loading derivation. In addition, this phase of loading derivation must detect the following errors:

    • If any of the classes or interfaces named as direct superinterfaces of C is not in fact an interface, loading throws an IncompatibleClassChangeError.

    • Otherwise, if any of the superinterfaces of C is C itself If the attempt to resolve a direct superinterface leads to the current thread attempting to recursively derive a class named N using loader L, loading derivation throws a ClassCircularityError.

    • Otherwise, if any of the classes or interfaces named as direct superinterfaces of C is not in fact an interface, derivation throws an IncompatibleClassChangeError.

    • Otherwise, for each direct superinterface, if the superinterface has a PermittedSubclasses attribute (4.7.30) and any of the following are true, derivation fails with a IncompatibleClassChangeError:

      • The superinterface belongs to a different run-time module than C.

      • C does not have its ACC_PUBLIC flag set (4.1) and the superinterface belongs to a different run-time package than C.

      • No entry in the classes table of the superinterface's PermittedSubclasses attribute references a class or interface with name N.

  5. If, since step 1, in another thread, the Java Virtual Machine has marked a class or interface named N as having L as its defining class loader, that class or interface is the result of class derivation, and the class or interface derived in steps 1-4 is discarded.

    This is the longstanding behavior of Hotspot, but there was no provision for it in the specification.

    The Otherwise, the class or interface derived in steps 1-4 is the result of class derivation, and the Java Virtual Machine marks C as having L as its defining class loader and records that L is an initiating loader of C (5.3.4).