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

Sealed Types (Preview)

Changes to the Java® Language Specification • Version 14-internal+0-adhoc.gbierman.20190830

This document describes changes to the Java Language Specification to support sealed types. See JEP 360.

Changes are described with respect to existing sections of the JLS. 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 8: Classes

Class declarations define new reference types and describe how they are implemented (8.1).

A top level class is a class that is not a nested class.

A nested class is any class whose declaration occurs within the body of another class or interface.

This chapter discusses the common semantics of all classes - top level (7.6) and nested (including member classes (8.5, 9.5), local classes (14.3) and anonymous classes (15.9.5)). Details that are specific to particular kinds of classes are discussed in the sections dedicated to these constructs.

A named class may be declared abstract (8.1.1.1) and must be declared abstract if it is incompletely implemented; such a class cannot be instantiated, but can be extended by subclasses.

The degree to which a class can be extended can be explictly controlled ( 8.1.1.2). A class may be declared sealed, in which case there is a fixed set of classes that directly extend the sealed class. A class may be declared final, in which case it cannot have any subclasses.

If a class is declared public, then it can be referred to from code in any package of its module and potentially from code in other modules. Each class except Object is an extension of (that is, a subclass of) a single existing class (8.1.4) and may implement interfaces (8.1.5). Classes may be generic (8.1.2), that is, they may declare type variables whose bindings may differ among different instances of the class.

Classes may be decorated with annotations (9.7) just like any other kind of declaration.

The body of a class declares members (fields and methods and nested classes and interfaces), instance and static initializers, and constructors (8.1.6). The scope (6.3) of a member (8.2) is the entire body of the declaration of the class to which the member belongs. Field, method, member class, member interface, and constructor declarations may include the access modifiers (6.6) public, protected, or private. The members of a class include both declared and inherited members (8.2). Newly declared fields can hide fields declared in a superclass or superinterface. Newly declared class members and interface members can hide class or interface members declared in a superclass or superinterface. Newly declared methods can hide, implement, or override methods declared in a superclass or superinterface.

Field declarations (8.3) describe class variables, which are incarnated once, and instance variables, which are freshly incarnated for each instance of the class. A field may be declared final (8.3.1.2), in which case it can be assigned to only once. Any field declaration may include an initializer.

Member class declarations (8.5) describe nested classes that are members of the surrounding class. Member classes may be static, in which case they have no access to the instance variables of the surrounding class; or they may be inner classes (8.1.3).

Member interface declarations (8.5) describe nested interfaces that are members of the surrounding class.

Method declarations (8.4) describe code that may be invoked by method invocation expressions (15.12). A class method is invoked relative to the class type; an instance method is invoked with respect to some particular object that is an instance of a class type. A method whose declaration does not indicate how it is implemented must be declared abstract. A method may be declared final (8.4.3.3), in which case it cannot be hidden or overridden. A method may be implemented by platform-dependent native code (8.4.3.4). A synchronized method (8.4.3.6) automatically locks an object before executing its body and automatically unlocks the object on return, as if by use of a synchronized statement (14.19), thus allowing its activities to be synchronized with those of other threads (17).

Method names may be overloaded (8.4.9).

Instance initializers (8.6) are blocks of executable code that may be used to help initialize an instance when it is created (15.9).

Static initializers (8.7) are blocks of executable code that may be used to help initialize a class.

Constructors (8.8) are similar to methods, but cannot be invoked directly by a method call; they are used to initialize new class instances. Like methods, they may be overloaded (8.8.8).

8.1 Class Declarations

A class declaration specifies a new named reference type.

There are two kinds of class declarations: normal class declarations and enum declarations.

ClassDeclaration:
NormalClassDeclaration
EnumDeclaration
NormalClassDeclaration:
{ClassModifier} class TypeIdentifier [TypeParameters]
[Superclass] [Superinterfaces]
[PermittedSubclasses] ClassBody

The rules in this section apply to all class declarations, including enum declarations. However, special rules apply to enum declarations with regard to class modifiers, inner classes, and superclasses; these rules are stated in 8.9.

The TypeIdentifier in a class declaration specifies the name of the class.

It is a compile-time error if a class has the same simple name as any of its enclosing classes or interfaces.

The scope and shadowing of a class declaration is specified in 6.3 and 6.4.

8.1.1 Class Modifiers

A class declaration may include class modifiers.

ClassModifier:
(one of)
Annotation public protected private
abstract static sealed non-sealed final strictfp

The rules for annotation modifiers on a class declaration are specified in 9.7.4 and 9.7.5.

The access modifier public (6.6) pertains only to top level classes (7.6) and member classes (8.5), not to local classes (14.3) or anonymous classes (15.9.5).

The access modifiers protected and private pertain only to member classes within a directly enclosing class declaration (8.5).

The modifier static pertains only to member classes (8.5.1), not to top level or local or anonymous classes.

It is a compile-time error if the same keyword appears more than once as a modifier for a class declaration, or if a class declaration has more than one of the access modifiers public, protected, and private (6.6).

It is a compile-time error if a class declaration has more than one of the class modifiers sealed, non-sealed and final.

If two or more (distinct) class modifiers appear in a class declaration, then it is customary, though not required, that they appear in the order consistent with that shown above in the production for ClassModifier.

8.1.1.2 sealed, non-sealed, and final Classes

This subsection has a new title.

Extensibility of class hierarchies is an important feature of object-oriented programming. However, there are circumstances where explicit control of this extensibility is desirable.

A class can be declared sealed when it is useful to restrict its subclasses to a fixed set of classes.

A class can be declared final if its definition is complete and no subclasses are desired or required.

In certain circumstances, a class can be declared non-sealed to allow unrestricted subclasses.

If a class C extends a sealed class (8.1.4) that is declared in the same compilation unit (7.3), or implements a sealed interface (9.1.1.3) that is declared in the same compilation unit, one of the following applies:

Otherwise, if a class C extends a sealed class or implements a sealed interface, one of the following applies:

It is a compile-time error if a class that does not extend a sealed class or implement a sealed interface is declared non-sealed.

It is a compile-time error if the name of a final class appears in the extends clause (8.1.4) of another class declaration; this implies that a final class cannot have any subclasses.

It is a compile-time error if a class is declared both final and abstract, because the implementation of such a class could never be completed (8.1.1.1).

Because a final class never has any subclasses, the methods of a final class are never overridden (8.4.8.1).

8.1.4 Superclasses and Subclasses

The optional extends clause in a normal class declaration specifies the direct superclass of the current class.

Superclass:
extends ClassType

The extends clause must not appear in the definition of the class Object, or a compile-time error occurs, because it is the primordial class and has no direct superclass.

The ClassType must name an accessible class type (6.6), or a compile-time error occurs.

It is a compile-time error if the ClassType names a sealed class and the current class is not a permitted subclass of ClassType (8.1.6).

It is a compile-time error if the ClassType names a class that is final, because final classes are not allowed to have subclasses (8.1.1.2).

It is a compile-time error if the ClassType names the class Enum or any invocation of Enum (8.9).

If the ClassType has type arguments, it must denote a well-formed parameterized type (4.5), and none of the type arguments may be wildcard type arguments, or a compile-time error occurs.

Given a (possibly generic) class declaration C<F1,...,Fn> (n 0, C Object), the direct superclass of the class type C<F1,...,Fn> is the type given in the extends clause of the declaration of C if an extends clause is present, or Object otherwise.

Given a generic class declaration C<F1,...,Fn> (n > 0), the direct superclass of the parameterized class type C<T1,...,Tn>, where Ti (1 i n) is a type, is D<U1 θ,...,Uk θ>, where D<U1,...,Uk> is the direct superclass of C<F1,...,Fn> and θ is the substitution [*F~1~*:=*T~1~*,...,*F~n~*:=*T~n~*].

A class is said to be a direct subclass of its direct superclass. The direct superclass is the class from whose implementation the implementation of the current class is derived.

The subclass relationship is the transitive closure of the direct subclass relationship. A class A is a subclass of class C if either of the following is true:

Class C is said to be a superclass of class A whenever A is a subclass of C.

Example 8.1.4-1. Direct Superclasses and Subclasses

class Point { int x, y; }
final class ColoredPoint extends Point { int color; }
class Colored3DPoint extends ColoredPoint { int z; }  // error

Here, the relationships are as follows:

The declaration of class Colored3dPoint causes a compile-time error because it attempts to extend the final class ColoredPoint.

Example 8.1.4-2. Superclasses and Subclasses

class Point { int x, y; }
class ColoredPoint extends Point { int color; }
final class Colored3dPoint extends ColoredPoint { int z; }

Here, the relationships are as follows:

A class C directly depends on a type T if T is mentioned in the extends or implements clause of C either as a superclass or superinterface, or as a qualifier in the fully qualified form of a superclass or superinterface name.

A class C depends on a reference type T if any of the following is true:

It is a compile-time error if a class depends on itself.

If circularly declared classes are detected at run time, as classes are loaded, then a ClassCircularityError is thrown (12.2.1).

Example 8.1.4-3. Class Depends on Itself

class Point extends ColoredPoint { int x, y; }
class ColoredPoint extends Point { int color; }

This program causes a compile-time error because class Point depends on itself.

8.1.5 Superinterfaces

The optional implements clause in a class declaration lists the names of interfaces that are direct superinterfaces of the class being declared.

Superinterfaces:
implements InterfaceTypeList
InterfaceTypeList:
InterfaceType {, InterfaceType}

Each InterfaceType must name an accessible interface type (6.6), or a compile-time error occurs.

It is a compile-time error if an InterfaceType names a sealed interface, and the class being declared is not a permitted subtype of InterfaceType (9.1.1.3).

If an InterfaceType has type arguments, it must denote a well-formed parameterized type (4.5), and none of the type arguments may be wildcard type arguments, or a compile-time error occurs.

It is a compile-time error if the same interface is mentioned as a direct superinterface more than once in a single implements clause. This is true even if the interface is named in different ways.

Example 8.1.5-1. Illegal Superinterfaces

class Redundant implements java.lang.Cloneable, Cloneable {
    int x;
}

This program results in a compile-time error because the names java.lang.Cloneable and Cloneable refer to the same interface.

Given a (possibly generic) class declaration C<F1,...,Fn> (n 0, C Object), the direct superinterfaces of the class type C<F1,...,Fn> are the types given in the implements clause of the declaration of C, if an implements clause is present.

Given a generic class declaration C<F1,...,Fn> (n > 0), the direct superinterfaces of the parameterized class type C<T1,...,Tn>, where Ti (1 i n) is a type, are all types I<U1 θ,...,Uk θ>, where I<U1,...,Uk> is a direct superinterface of C<F1,...,Fn> and θ is the substitution [*F~1~*:=*T~1~*,...,*F~n~*:=*T~n~*].

An interface type I is a superinterface of class type C if any of the following is true:

A class can have a superinterface in more than one way.

A class is said to implement all its superinterfaces.

A class may not at the same time be a subtype of two interface types which are different parameterizations of the same generic interface (9.1.2), or a subtype of a parameterization of a generic interface and a raw type naming that same generic interface, or a compile-time error occurs.

This requirement was introduced in order to support translation by type erasure (4.6).

Example 8.1.5-2. Superinterfaces

interface Colorable {
    void setColor(int color);
    int getColor();
}
enum Finish { MATTE, GLOSSY }
interface Paintable extends Colorable {
    void setFinish(Finish finish);
    Finish getFinish();
}

class Point { int x, y; }
class ColoredPoint extends Point implements Colorable {
    int color;
    public void setColor(int color) { this.color = color; }
    public int getColor() { return color; }
}
class PaintedPoint extends ColoredPoint implements Paintable {
    Finish finish;
    public void setFinish(Finish finish) {
        this.finish = finish;
    }
    public Finish getFinish() { return finish; }
}

Here, the relationships are as follows:

The class PaintedPoint has Colorable as a superinterface both because it is a superinterface of ColoredPoint and because it is a superinterface of Paintable.

Example 8.1.5-3. Illegal Multiple Inheritance of an Interface

interface I<T> {}
class B implements I<Integer> {}
class C extends B implements I<String> {}

Class C causes a compile-time error because it attempts to be a subtype of both I<Integer> and I<String>.

Unless the class being declared is abstract, all the abstract member methods of each direct superinterface must be implemented (8.4.8.1) either by a declaration in this class or by an existing method declaration inherited from the direct superclass or a direct superinterface, because a class that is not abstract is not permitted to have abstract methods (8.1.1.1).

Each default method (9.4.3) of a superinterface of the class may optionally be overridden by a method in the class; if not, the default method is typically inherited and its behavior is as specified by its default body.

It is permitted for a single method declaration in a class to implement methods of more than one superinterface.

Example 8.1.5-3. Implementing Methods of a Superinterface

interface Colorable {
    void setColor(int color);
    int getColor();
}
class Point { int x, y; };
class ColoredPoint extends Point implements Colorable {
    int color;
}

This program causes a compile-time error, because ColoredPoint is not an abstract class but fails to provide an implementation of methods setColor and getColor of the interface Colorable.

In the following program:

interface Fish  { int getNumberOfScales(); }
interface Piano { int getNumberOfScales(); }
class Tuna implements Fish, Piano {
    // You can tune a piano, but can you tuna fish?
    public int getNumberOfScales() { return 91; }
}

the method getNumberOfScales in class Tuna has a name, signature, and return type that matches the method declared in interface Fish and also matches the method declared in interface Piano; it is considered to implement both.

On the other hand, in a situation such as this:

interface Fish       { int    getNumberOfScales(); }
interface StringBass { double getNumberOfScales(); }
class Bass implements Fish, StringBass {
    // This declaration cannot be correct,
    // no matter what type is used.
    public ?? getNumberOfScales() { return 91; }
}

it is impossible to declare a method named getNumberOfScales whose signature and return type are compatible with those of both the methods declared in interface Fish and in interface StringBass, because a class cannot have multiple methods with the same signature and different primitive return types (8.4). Therefore, it is impossible for a single class to implement both interface Fish and interface StringBass (8.4.8).

8.1.6 Permitted subclasses

This is a new subsection. The existing subsection 8.1.6 "Class Body and Member Declarations" is renumbered to 8.1.7.

A sealed class can restrict its subclasses to a fixed set of classes. The permitted subclasses of a sealed class C are declared in a permits clause. A sealed class C may have an explicitly declared permits clause, which provides a non-empty list of the permitted subclasses of C.

PermittedSubclasses
permits TypeName {, TypeName }

Every TypeName must denote a class type that is accessible (6.6). It is a compile-time error if any TypeName denotes a class type that is not accessible, or denotes a type variable.

A sealed class C without an explicitly declared permits clause, has an implicitly declared permits clause that lists as permitted subclasses all the classes in the same compilation unit (7.3) as C that declare C as their direct superclass.

Declaring a sealed class that has no direct subclasses in the same compilation unit without an explicit permits clause, is equivalent to declaring the class final, i.e. it cannot have any direct subclasses.

It is a compile-time error if a class is declared both abstract and sealed, and has no permitted subclasses, because the implementation of such a class could never be completed (8.1.1.1).

It is a compile-time error if any permitted subclass of a sealed class C is not a member of the same module as C. If the sealed class C is a member of the unnamed module, then it is a compile-time error if any permitted subclass is not in the same package as C.

It is a compile-time error if a class that is not sealed has a permits clause.

Chapter 9: Interfaces

An interface declaration introduces a new reference type whose members are classes, interfaces, constants, and methods. This type has no instance variables, and typically declares one or more abstract methods; otherwise unrelated classes can implement the interface by providing implementations for its abstract methods. Interfaces may not be directly instantiated.

A nested interface is any interface whose declaration occurs within the body of another class or interface.

A top level interface is an interface that is not a nested interface.

We distinguish between two kinds of interfaces - normal interfaces and annotation types.

This chapter discusses the common semantics of all interfaces - normal interfaces, both top level (7.6) and nested (8.5, 9.5), and annotation types (9.6). Details that are specific to particular kinds of interfaces are discussed in the sections dedicated to these constructs.

Programs can use interfaces to make it unnecessary for related classes to share a common abstract superclass or to add methods to Object.

An interface may be declared to be a direct extension of one or more other interfaces, meaning that it inherits all the member types, instance methods, and constants of the interfaces it extends, except for any members that it may override or hide.

A class may be declared to directly implement one or more interfaces, meaning that any instance of the class implements all the abstract methods specified by the interface or interfaces. A class necessarily implements all the interfaces that its direct superclasses and direct superinterfaces do. This (multiple) interface inheritance allows objects to support (multiple) common behaviors without sharing a superclass.

Unlike a class, an interface cannot be declared final. However, an interface may be declared sealed (9.1.1.3), in which case it specifies a fixed set of classes and interfaces that directly implement or extend the sealed interface.

A variable whose declared type is an interface type may have as its value a reference to any instance of a class which implements the specified interface. It is not sufficient that the class happen to implement all the abstract methods of the interface; the class or one of its superclasses must actually be declared to implement the interface, or else the class is not considered to implement the interface.

9.1 Interface Declarations

An interface declaration specifies a new named reference type. There are two kinds of interface declarations - normal interface declarations and annotation type declarations (9.6).

InterfaceDeclaration:
NormalInterfaceDeclaration
AnnotationTypeDeclaration
NormalInterfaceDeclaration:
{InterfaceModifier} interface TypeIdentifier [TypeParameters]
[ExtendsInterfaces] [PermittedSubtypes] InterfaceBody

The TypeIdentifier in an interface declaration specifies the name of the interface.

It is a compile-time error if an interface has the same simple name as any of its enclosing classes or interfaces.

The scope and shadowing of an interface declaration is specified in 6.3 and 6.4.

9.1.1 Interface Modifiers

An interface declaration may include interface modifiers.

InterfaceModifier:
(one of)
Annotation public protected private
abstract static sealed non-sealed strictfp

The rules for annotation modifiers on an interface declaration are specified in 9.7.4 and 9.7.5.

The access modifier public (6.6) pertains to every kind of interface declaration.

The access modifiers protected and private pertain only to member interfaces whose declarations are directly enclosed by a class declaration (8.5.1).

The modifier static pertains only to member interfaces (8.5.1, 9.5), not to top level interfaces (7.6).

It is a compile-time error if the same keyword appears more than once as a modifier for an interface declaration, or if a interface declaration has more than one of the access modifiers public, protected, and private (6.6).

It is a compile-time error if an interface declaration has more than one of the interface modifiers sealed, and non-sealed.

If two or more (distinct) interface modifiers appear in an interface declaration, then it is customary, though not required, that they appear in the order consistent with that shown above in the production for InterfaceModifier.

9.1.1.3 sealed and non-sealed Interfaces

This is a new section.

An interface can be declared sealed when it is useful to restrict its subtypes to a fixed set of classes and interfaces.

In certain circumstances, an interface can be declared non-sealed to allow unrestricted subtypes.

If an interface I extends a sealed interface (9.1.3), one of the following applies:

It is a compile-time error if an interface that does not extend a sealed interface is declared non-sealed.

9.1.3 Superinterfaces and Subinterfaces

If an extends clause is provided, then the interface being declared extends each of the other named interfaces and therefore inherits the member types, instance methods, and constants of each of the other named interfaces.

These other named interfaces are the direct superinterfaces of the interface being declared.

Any class that implements the declared interface is also considered to implement all the interfaces that this interface extends.

ExtendsInterfaces:
extends InterfaceTypeList

The following production from 8.1.5 is shown here for convenience:

InterfaceTypeList:
InterfaceType {, InterfaceType}

Each InterfaceType in the extends clause of an interface declaration must name an accessible interface type (6.6), or a compile-time error occurs.

It is a compile-time error if an InterfaceType names an interface that is sealed, and the interface being declared is not a permitted subtype of InterfaceType (9.1.4).

If an InterfaceType has type arguments, it must denote a well-formed parameterized type (4.5), and none of the type arguments may be wildcard type arguments, or a compile-time error occurs.

Given a (possibly generic) interface declaration I<F1,...,Fn> (n 0), the direct superinterfaces of the interface type I<F1,...,Fn> are the types given in the extends clause of the declaration of I, if an extends clause is present.

Given a generic interface declaration I<F1,...,Fn> (n > 0), the direct superinterfaces of the parameterized interface type I<T1,...,Tn>, where Ti (1 i n) is a type, are all types J<U1 θ,...,Uk θ>, where J<U1,...,Uk> is a direct superinterface of I<F1,...,Fn> and θ is the substitution [*F~1~*:=*T~1~*,...,*F~n~*:=*T~n~*].

The superinterface relationship is the transitive closure of the direct superinterface relationship. An interface K is a superinterface of interface I if either of the following is true:

Interface I is said to be a subinterface of interface K whenever K is a superinterface of I.

While every class is an extension of class Object, there is no single interface of which all interfaces are extensions.

An interface I directly depends on a type T if T is mentioned in the extends clause of I either as a superinterface or as a qualifier in the fully qualified form of a superinterface name.

An interface I depends on a reference type T if any of the following is true:

It is a compile-time error if an interface depends on itself.

If circularly declared interfaces are detected at run time, as interfaces are loaded, then a ClassCircularityError is thrown (12.2.1).

9.1.4 Permitted Subtypes

This is a new subsection. The existing subsection 9.1.4 "Interface Body and Member Declarations" is renumbered to 9.1.5.

The permitted subtypes of a sealed interface are specified using a permits clause. A sealed interface I may have an explicit permits clause, which provides a non-empty list of the permitted subtypes of I (i.e. the classes that directly implement I and the interfaces that directly extend I).

PermittedSubtypes
permits TypeName {, TypeName }

Every TypeName must denote a class or interface type that is accessible ( 6.6). It is a compile-time error if any TypeName denotes a class or interface type that is not accessible, or denotes a type variable.

If a sealed interface I does not have an explicit permits clause, then it has an implicitly declared permits clause that lists as permitted subtypes all the classes and interfaces in the same compilation unit (7.3) as I that declare I as their direct superinterface.

It is a compile-time error if a sealed interface has no permitted subtypes.

It is a compile-time error if any permitted subtype of a sealed interface I is not a member of the same module as I. If the sealed interface I is a member of the unnamed module, then it is a compile-time error if any permitted subtype is not in the same package as the interface I.

It is a compile-time error if an interface declaration has an explicit permits clause but is not sealed.

Chapter 13: Binary Compatibility

To be completed.