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

Records

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

This document describes changes to the Java Language Specification to support records, a preview feature of Java SE 14. See JEP 359 for an overview of the feature.

A companion document describes the changes needed to the Java Virtual Machine Specification to support records.

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 1: Introduction

1.1 Organization of the Specification

Chapter 2 describes grammars and the notation used to present the lexical and syntactic grammars for the language.

Chapter 3 describes the lexical structure of the Java programming language, which is based on C and C++. The language is written in the Unicode character set. It supports the writing of Unicode characters on systems that support only ASCII.

Chapter 4 describes types, values, and variables. Types are subdivided into primitive types and reference types.

The primitive types are defined to be the same on all machines and in all implementations, and are various sizes of two's-complement integers, single- and double-precision IEEE 754 standard floating-point numbers, a boolean type, and a Unicode character char type. Values of the primitive types do not share state.

Reference types are the class types, the interface types, and the array types. The reference types are implemented by dynamically created objects that are either instances of classes or arrays. Many references to each object can exist. All objects (including arrays) support the methods of the class Object, which is the (single) root of the class hierarchy. A predefined String class supports Unicode character strings. Classes exist for wrapping primitive values inside of objects. In many cases, wrapping and unwrapping is performed automatically by the compiler (in which case, wrapping is called boxing, and unwrapping is called unboxing). Class and interface declarations may be generic, that is, they may be parameterized by other reference types. Such declarations may then be invoked with specific type arguments.

Variables are typed storage locations. A variable of a primitive type holds a value of that exact primitive type. A variable of a class type can hold a null reference or a reference to an object whose type is that class type or any subclass of that class type. A variable of an interface type can hold a null reference or a reference to an instance of any class that implements the interface. A variable of an array type can hold a null reference or a reference to an array. A variable of class type Object can hold a null reference or a reference to any object, whether class instance or array.

Chapter 5 describes conversions and numeric promotions. Conversions change the compile-time type and, sometimes, the value of an expression. These conversions include the boxing and unboxing conversions between primitive types and reference types. Numeric promotions are used to convert the operands of a numeric operator to a common type where an operation can be performed. There are no loopholes in the language; casts on reference types are checked at run time to ensure type safety.

Chapter 6 describes declarations and names, and how to determine what names mean (that is, which declaration a name denotes). The Java programming language does not require classes and interfaces, or their members, to be declared before they are used. Declaration order is significant only for local variables, local classes, and the order of field initializers in a class or interface. Recommended naming conventions that make for more readable programs are described here.

Chapter 7 describes the structure of a program, which is organized into packages. The members of a package are classes, interfaces, and subpackages. Packages, and consequently their members, have names in a hierarchical name space; the Internet domain name system can usually be used to form unique package names. Compilation units contain declarations of the classes and interfaces that are members of a given package, and may import classes and interfaces from other packages to give them short names.

Packages may be grouped into modules that serve as building blocks in the construction of very large programs. The declaration of a module specifies which other modules (and thus packages, and thus classes and interfaces) are required in order to compile and run code in its own packages.

The Java programming language supports limitations on external access to the members of packages, classes, and interfaces. The members of a package may be accessible solely by other members in the same package, or by members in other packages of the same module, or by members of packages in different modules. Similar constraints apply to the members of classes and interfaces.

Chapter 8 describes classes. The members of classes are classes, interfaces, fields (variables) and methods. Class variables exist once per class. Class methods operate without reference to a specific object. Instance variables are dynamically created in objects that are instances of classes. Instance methods are invoked on instances of classes; such instances become the current object this during their execution, supporting the object-oriented programming style.

Classes support single inheritance, in which each class has a single superclass. Each class inherits members from its superclass, and ultimately from the class Object. Variables of a class type can reference an instance of that class or of any subclass of that class, allowing new types to be used with existing methods, polymorphically.

Classes support concurrent programming with synchronized methods. Methods declare the checked exceptions that can arise from their execution, which allows compile-time checking to ensure that exceptional conditions are handled. Objects can declare a finalize method that will be invoked before the objects are discarded by the garbage collector, allowing the objects to clean up their state.

For simplicity, the language has neither declaration "headers" separate from the implementation of a class nor separate type and class hierarchies.

Enums are a special kind of class that support the definition of small sets of values which can then be used in a type safe manner. A special form of classes, enums, support the definition of small sets of values and their manipulation in a type safe manner. Unlike enumerations in other languages, enums are objects and may have their own methods.

Records are another special kind of class that support the compact expression of simple objects that serve as aggregates of values.

Chapter 9 describes interfaces. The members of interfaces are classes, interfaces, constant fields, and methods. Classes that are otherwise unrelated can implement the same interface. A variable of an interface type can contain a reference to any object that implements the interface.

Classes and interfaces support multiple inheritance from interfaces. A class that implements one or more interfaces may inherit instance methods from both its superclass and its superinterfaces.

Annotation types are specialized interfaces used to annotate declarations. Such annotations are not permitted to affect the semantics of programs in the Java programming language in any way. However, they provide useful input to various tools.

Chapter 10 describes arrays. Array accesses include bounds checking. Arrays are dynamically created objects and may be assigned to variables of type Object. The language supports arrays of arrays, rather than multidimensional arrays.

Chapter 11 describes exceptions, which are nonresuming and fully integrated with the language semantics and concurrency mechanisms. There are three kinds of exceptions: checked exceptions, run-time exceptions, and errors. The compiler ensures that checked exceptions are properly handled by requiring that a method or constructor can result in a checked exception only if the method or constructor declares it. This provides compile-time checking that exception handlers exist, and aids programming in the large. Most user-defined exceptions should be checked exceptions. Invalid operations in the program detected by the Java Virtual Machine result in run-time exceptions, such as NullPointerException. Errors result from failures detected by the Java Virtual Machine, such as OutOfMemoryError. Most simple programs do not try to handle errors.

Chapter 12 describes activities that occur during execution of a program. A program is normally stored as binary files representing compiled classes and interfaces. These binary files can be loaded into a Java Virtual Machine, linked to other classes and interfaces, and initialized.

After initialization, class methods and class variables may be used. Some classes may be instantiated to create new objects of the class type. Objects that are class instances also contain an instance of each superclass of the class, and object creation involves recursive creation of these superclass instances.

When an object is no longer referenced, it may be reclaimed by the garbage collector. If an object declares a finalizer, the finalizer is executed before the object is reclaimed to give the object a last chance to clean up resources that would not otherwise be released. When a class is no longer needed, it may be unloaded.

Chapter 13 describes binary compatibility, specifying the impact of changes to types on other types that use the changed types but have not been recompiled. These considerations are of interest to developers of types that are to be widely distributed, in a continuing series of versions, often through the Internet. Good program development environments automatically recompile dependent code whenever a type is changed, so most programmers need not be concerned about these details.

Chapter 14 describes blocks and statements, which are based on C and C++. The language has no goto statement, but includes labeled break and continue statements. Unlike C, the Java programming language requires boolean (or Boolean) expressions in control-flow statements, and does not convert types to boolean implicitly (except through unboxing), in the hope of catching more errors at compile time. A synchronized statement provides basic object-level monitor locking. A try statement can include catch and finally clauses to protect against non-local control transfers.

Chapter 15 describes expressions. This document fully specifies the (apparent) order of evaluation of expressions, for increased determinism and portability. Overloaded methods and constructors are resolved at compile time by picking the most specific method or constructor from those which are applicable.

Chapter 16 describes the precise way in which the language ensures that local variables are definitely set before use. While all other variables are automatically initialized to a default value, the Java programming language does not automatically initialize local variables in order to avoid masking programming errors.

Chapter 17 describes the semantics of threads and locks, which are based on the monitor-based concurrency originally introduced with the Mesa programming language. The Java programming language specifies a memory model for shared-memory multiprocessors that supports high-performance implementations.

Chapter 18 describes a variety of type inference algorithms used to test applicability of generic methods and to infer types in a generic method invocation.

Chapter 19 presents a syntactic grammar for the language.

1.5 Preview Features

The following text will be added to the description of the preview feature: Record Types.

The following are essential API elements associated with Record Types:

Chapter 3: Lexical Structure

3.8 Identifiers

An identifier is an unlimited-length sequence of Java letters and Java digits, the first of which must be a Java letter.

Identifier:
IdentifierChars but not a Keyword or BooleanLiteral or NullLiteral
IdentifierChars:
JavaLetter {JavaLetterOrDigit}
JavaLetter:
any Unicode character that is a "Java letter"
JavaLetterOrDigit:
any Unicode character that is a "Java letter-or-digit"

A "Java letter" is a character for which the method Character.isJavaIdentifierStart(int) returns true.

A "Java letter-or-digit" is a character for which the method Character.isJavaIdentifierPart(int) returns true.

The "Java letters" include uppercase and lowercase ASCII Latin letters A-Z (\u0041-\u005a), and a-z (\u0061-\u007a), and, for historical reasons, the ASCII dollar sign ($, or \u0024) and underscore (_, or \u005f). The dollar sign should be used only in mechanically generated source code or, rarely, to access pre-existing names on legacy systems. The underscore may be used in identifiers formed of two or more characters, but it cannot be used as a one-character identifier due to being a keyword.

The "Java digits" include the ASCII digits 0-9 (\u0030-\u0039).

Letters and digits may be drawn from the entire Unicode character set, which supports most writing scripts in use in the world today, including the large sets for Chinese, Japanese, and Korean. This allows programmers to use identifiers in their programs that are written in their native languages.

An identifier cannot have the same spelling (Unicode character sequence) as a keyword (3.9), boolean literal (3.10.3), or the null literal (3.10.7), or a compile-time error occurs.

Two identifiers are the same only if, after ignoring characters that are ignorable, the identifiers have the same Unicode character for each letter or digit. An ignorable character is a character for which the method Character.isIdentifierIgnorable(int) returns true. Identifiers that have the same external appearance may yet be different.

For example, the identifiers consisting of the single letters LATIN CAPITAL LETTER A (A, \u0041), LATIN SMALL LETTER A (a, \u0061), GREEK CAPITAL LETTER ALPHA (A, \u0391), CYRILLIC SMALL LETTER A (a, \u0430) and MATHEMATICAL BOLD ITALIC SMALL A (a, \ud835\udc82) are all different.

Unicode composite characters are different from their canonical equivalent decomposed characters. For example, a LATIN CAPITAL LETTER A ACUTE (Á, \u00c1) is different from a LATIN CAPITAL LETTER A (A, \u0041) immediately followed by a NON-SPACING ACUTE (´, \u0301) in identifiers. See The Unicode Standard, Section 3.11 "Normalization Forms".

Examples of identifiers are:

The identifiers var and record are restricted identifiers because they are not allowed in some contexts.

In another JEP (JEP 361: Switch Expressions) targetting JDK14, it is proposed to additionally make the identifier yield a restricted identifier.

A type identifier is an identifier that is not neither the character sequence var nor the character sequence record.

TypeIdentifier:
Identifier but not var or record

Type identifiers are used in certain contexts involving the declaration or use of types. For example, the name of a class must be a TypeIdentifier, so it is illegal to declare a class named var or record (8.1).

3.9 Keywords

51 character sequences, formed from ASCII letters, are reserved for use as keywords and cannot be used as identifiers (3.8).

Keyword:
(one of)
abstract continue for new switch
assert default if package synchronized
boolean do goto private this
break double implements protected throw
byte else import public throws
case enum instanceof return transient
catch extends int short try
char final interface static void
class finally long strictfp volatile
const float native super while
_ (underscore)

The keywords const and goto are reserved, even though they are not currently used. This may allow a Java compiler to produce better error messages if these C++ keywords incorrectly appear in programs.

A variety of character sequences are sometimes assumed, incorrectly, to be keywords:

A further ten character sequences are restricted keywords: open, module, requires, transitive, exports, opens, to, uses, provides, and with. These character sequences are tokenized as keywords solely where they appear as terminals in the ModuleDeclaration, ModuleDirective, and RequiresModifier productions (7.7). They are tokenized as identifiers everywhere else, for compatibility with programs written before the introduction of restricted keywords. There is one exception: immediately to the right of the character sequence requires in the ModuleDirective production, the character sequence transitive is tokenized as a keyword unless it is followed by a separator, in which case it is tokenized as an identifier.

Chapter 4: Types, Values, and Variables

4.11 Where Types Are Used

Types are used in most kinds of declaration and in certain kinds of expression. Specifically, there are 16 17 type contexts where types are used:

Also, types are used as:

Finally, there are three special terms in the Java programming language which denote the use of a type:

The meaning of types in type contexts is given by:

Some type contexts restrict how a reference type may be parameterized:

In any type context where a type is used, it is possible to annotate the keyword denoting a primitive type or the Identifier denoting the simple name of a reference type. It is also possible to annotate an array type by writing an annotation to the left of the [ at the desired level of nesting in the array type. Annotations in these locations are called type annotations, and are specified in 9.7.4. Here are some examples:

Five Six of the type contexts which appear in declarations occupy the same syntactic real estate as a number of declaration contexts (9.6.4.1):

The fact that the same syntactic location in a program can be both a type context and a declaration context arises because the modifiers for a declaration immediately precede the type of the declared entity. 9.7.4 explains how an annotation in such a location is deemed to appear in a type context or a declaration context or both.

Example 4.11-1. Usage of a Type

import java.util.Random;
import java.util.Collection;
import java.util.ArrayList;

class MiscMath<T extends Number> {
    int divisor;
    MiscMath(int divisor) { this.divisor = divisor; }
    float ratio(long l) {
        try {
            l /= divisor;
        } catch (Exception e) {
            if (e instanceof ArithmeticException)
                l = Long.MAX_VALUE;
            else
                l = 0;
        }
        return (float)l;
    }
    double gausser() {
        Random r = new Random();
        double[] val = new double[2];
        val[0] = r.nextGaussian();
        val[1] = r.nextGaussian();
        return (val[0] + val[1]) / 2;
    }
    Collection<Number> fromArray(Number[] na) {
        Collection<Number> cn = new ArrayList<Number>();
        for (Number n : na) cn.add(n);
        return cn;
    }
    <S> void loop(S s) { this.<S>loop(s); }  
}

In this example, types are used in declarations of the following:

and in expressions of the following kinds:

4.12 Variables

4.12.3 Kinds of Variables

There are eight kinds of variables:

  1. A class variable is a field declared using the keyword static within a class declaration (8.3.1.1), or with or without the keyword static within an interface declaration (9.3).

    A class variable is created when its class or interface is prepared (12.3.2) and is initialized to a default value (4.12.5). The class variable effectively ceases to exist when its class or interface is unloaded (12.7).

  2. An instance variable is a field declared explicitly or implicitly within a class declaration without using the keyword static (8.3.1.1).

    If a class T has a field a that is an instance variable, then a new instance variable a is created and initialized to a default value (4.12.5) as part of each newly created object of class T or of any class that is a subclass of T (8.1.4). The instance variable effectively ceases to exist when the object of which it is a field is no longer referenced, after any necessary finalization of the object (12.6) has been completed.

  3. Array components are unnamed variables that are created and initialized to default values (4.12.5) whenever a new object that is an array is created (10, 15.10.2). The array components effectively cease to exist when the array is no longer referenced.

  4. Method parameters (8.4.1) name argument values passed to a method.

    For every parameter declared in a method declaration, a new parameter variable is created each time that method is invoked (15.12). The new variable is initialized with the corresponding argument value from the method invocation. The method parameter effectively ceases to exist when the execution of the body of the method is complete.

  5. Constructor parameters (8.8.1) name argument values passed to a constructor.

    For every parameter declared in a constructor declaration, a new parameter variable is created each time a class instance creation expression (15.9) or explicit constructor invocation (8.8.7) invokes that constructor. The new variable is initialized with the corresponding argument value from the creation expression or constructor invocation. The constructor parameter effectively ceases to exist when the execution of the body of the constructor is complete.

  6. Lambda parameters (15.27.1) name argument values passed to a lambda expression body (15.27.2).

    For every parameter declared in a lambda expression, a new parameter variable is created each time a method implemented by the lambda body is invoked (15.12). The new variable is initialized with the corresponding argument value from the method invocation. The lambda parameter effectively ceases to exist when the execution of the lambda expression body is complete.

  7. An exception parameter is created each time an exception is caught by a catch clause of a try statement (14.20).

    The new variable is initialized with the actual object associated with the exception (11.3, 14.18). The exception parameter effectively ceases to exist when execution of the block associated with the catch clause is complete.

  8. Local variables are declared by local variable declaration statements (14.4).

    Whenever the flow of control enters a block (14.2) or for statement (14.14), a new variable is created for each local variable declared in a local variable declaration statement immediately contained within that block or for statement.

    A local variable declaration statement may contain an expression which initializes the variable. The local variable with an initializing expression is not initialized, however, until the local variable declaration statement that declares it is executed. (The rules of definite assignment (16) prevent the value of a local variable from being used before it has been initialized or otherwise assigned a value.) The local variable effectively ceases to exist when the execution of the block or for statement is complete.

    Were it not for one exceptional situation, a local variable could always be regarded as being created when its local variable declaration statement is executed. The exceptional situation involves the switch statement (14.11), where it is possible for control to enter a block but bypass execution of a local variable declaration statement. Because of the restrictions imposed by the rules of definite assignment (16), however, the local variable declared by such a bypassed local variable declaration statement cannot be used before it has been definitely assigned a value by an assignment expression (15.26).

Example 4.12.3-1. Different Kinds of Variables

class Point {
    static int numPoints;   // numPoints is a class variable
    int x, y;               // x and y are instance variables
    int[] w = new int[10];  // w[0] is an array component
    int setX(int x) {       // x is a method parameter
        int oldx = this.x;  // oldx is a local variable
        this.x = x;
        return oldx;
    }
}

4.12.4 final Variables

A variable can be declared final. A final variable may only be assigned to once. It is a compile-time error if a final variable is assigned to unless it is definitely unassigned immediately prior to the assignment (16).

Once a final variable has been assigned, it always contains the same value. If a final variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object. This applies also to arrays, because arrays are objects; if a final variable holds a reference to an array, then the components of the array may be changed by operations on the array, but the variable will always refer to the same array.

A blank final is a final variable whose declaration lacks an initializer.

A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (15.28). Whether a variable is a constant variable or not may have implications with respect to class initialization (12.4.1), binary compatibility (13.1), reachability (14.21), and definite assignment (16.1.1).

Three Four kinds of variable are implicitly declared final: a field of an interface (9.3), a local variable declared as a resource of a try-with-resources statement (14.20.3), and an exception parameter of a multi-catch clause (14.20), and the field corresponding to a record component (8.10.1). An exception parameter of a uni-catch clause is never implicitly declared final, but may be effectively final.

Example 4.12.4-1. Final Variables

Declaring a variable final can serve as useful documentation that its value will not change and can help avoid programming errors. In this program:

class Point {
    int x, y;
    int useCount;
    Point(int x, int y) { this.x = x; this.y = y; }
    static final Point origin = new Point(0, 0);
}

the class Point declares a final class variable origin. The origin variable holds a reference to an object that is an instance of class Point whose coordinates are (0, 0). The value of the variable Point.origin can never change, so it always refers to the same Point object, the one created by its initializer. However, an operation on this Point object might change its state - for example, modifying its useCount or even, misleadingly, its x or y coordinate.

Certain variables that are not declared final are instead considered effectively final:

If a variable is effectively final, adding the final modifier to its declaration will not introduce any compile-time errors. Conversely, a local variable or parameter that is declared final in a valid program becomes effectively final if the final modifier is removed.

Chapter 6: Names

Names are used to refer to entities declared in a program.

A declared entity (6.1) is a package, class type (normal, or enum, or record), interface type (normal or annotation type), member (class, interface, field, or method) of a reference type, type parameter (of a class, interface, method or constructor), parameter (to a method, constructor, or exception handler), or local variable.

Names in programs are either simple, consisting of a single identifier, or qualified, consisting of a sequence of identifiers separated by "." tokens (6.2).

Every declaration that introduces a name has a scope (6.3), which is the part of the program text within which the declared entity can be referred to by a simple name.

A qualified name N.x may be used to refer to a member of a package or reference type, where N is a simple or qualified name and x is an identifier. If N names a package, then x is a member of that package, which is either a class or interface type or a subpackage. If N names a reference type or a variable of a reference type, then x names a member of that type, which is either a class, an interface, a field, or a method.

In determining the meaning of a name (6.5), the context of the occurrence is used to disambiguate among packages, types, variables, and methods with the same name.

Access control (6.6) can be specified in a class, interface, method, or field declaration to control when access to a member is allowed. Access is a different concept from scope. Access specifies the part of the program text within which the declared entity can be referred to by a qualified name. Access to a declared entity is also relevant in a field access expression (15.11), a method invocation expression in which the method is not specified by a simple name (15.12), a method reference expression (15.13), or a qualified class instance creation expression (15.9). In the absence of an access modifier, most declarations have package access, allowing access anywhere within the package that contains its declaration; other possibilities are public, protected, and private.

Fully qualified and canonical names (6.7) are also discussed in this chapter.

6.1 Declarations

A declaration introduces an entity into a program and includes an identifier (3.8) that can be used in a name to refer to this entity. The identifier is constrained to be a type identifier when the entity being introduced is a class, interface, or type parameter.

A declared entity is one of the following:

Constructors (8.8) are also introduced by declarations, but use the name of the class in which they are declared rather than introducing a new name.

The declaration of a type which is not generic (class C ...) declares one entity: a non-generic type (C). A non-generic type is not a raw type, despite the syntactic similarity. In contrast, the declaration of a generic type (class C<T> ... or interface C<T> ...) declares two entities: a generic type (C<T>) and a corresponding non-generic type (C). In this case, the meaning of the term C depends on the context where it appears:

The 14 non-generic contexts are as follows:

  1. In a uses or provides directive in a module declaration (7.7.1)

  2. In a single-type-import declaration (7.5.1)

  3. To the left of the . in a single-static-import declaration (7.5.3)

  4. To the left of the . in a static-import-on-demand declaration (7.5.4)

  5. To the left of the ( in a constructor declaration (8.8)

  6. After the @ sign in an annotation (9.7)

  7. To the left of .class in a class literal (15.8.2)

  8. To the left of .this in a qualified this expression (15.8.4)

  9. To the left of .super in a qualified superclass field access expression (15.11.2)

  10. To the left of .Identifier or .super.Identifier in a qualified method invocation expression (15.12)

  11. To the left of .super:: in a method reference expression (15.13)

  12. In a qualified expression name in a postfix expression or a try-with-resources statement (15.14.1, 14.20.3)

  13. In a throws clause of a method or constructor (8.4.6, 8.8.5, 9.4)

  14. In an exception parameter declaration (14.20)

The first eleven non-generic contexts correspond to the first eleven syntactic contexts for a TypeName in 6.5.1. The twelfth non-generic context is where a qualified ExpressionName such as C.x may include a TypeName C to denote static member access. The common use of TypeName in these twelve contexts is significant: it indicates that these contexts involve a less-than-first-class use of a type. In contrast, the thirteenth and fourteenth non-generic contexts employ ClassType, indicating that throws and catch clauses use types in a first-class way, in line with, say, field declarations. The characterization of these two contexts as non-generic is due to the fact that an exception type cannot be parameterized.

Note that the ClassType production allows annotations, so it is possible to annotate the use of a type in a throws or catch clause, whereas the TypeName production disallows annotations, so it is not possible to annotate the name of a type in, say, a single-type-import declaration.

Naming Conventions

The class libraries of the Java SE Platform attempt to use, whenever possible, names chosen according to the conventions presented below. These conventions help to make code more readable and avoid certain kinds of name conflicts.

We recommend these conventions for use in all programs written in the Java programming language. However, these conventions should not be followed slavishly if long-held conventional usage dictates otherwise. So, for example, the sin and cos methods of the class java.lang.Math have mathematically conventional names, even though these method names flout the convention suggested here because they are short and are not verbs.

Package Names and Module Names

Developers should take steps to avoid the possibility of two published packages having the same name by choosing unique package names for packages that are widely distributed. This allows packages to be easily and automatically installed and catalogued. This section specifies a suggested convention for generating such unique package names. Implementations of the Java SE Platform are encouraged to provide automatic support for converting a set of packages from local and casual package names to the unique name format described here.

If unique package names are not used, then package name conflicts may arise far from the point of creation of either of the conflicting packages. This may create a situation that is difficult or impossible for the user or programmer to resolve. The classes ClassLoader and ModuleLayer can be used to isolate packages with the same name from each other in those cases where the packages will have constrained interactions, but not in a way that is transparent to a naïve program.

You form a unique package name by first having (or belonging to an organization that has) an Internet domain name, such as oracle.com. You then reverse this name, component by component, to obtain, in this example, com.oracle, and use this as a prefix for your package names, using a convention developed within your organization to further administer package names. Such a convention might specify that certain package name components be division, department, project, machine, or login names.

Example 6.1-1. Unique Package Names

com.nighthacks.scrabble.dictionary
org.openjdk.compiler.source.tree
net.jcip.annotations
edu.cmu.cs.bovik.cheese
gov.whitehouse.socks.mousefinder

The first component of a unique package name is always written in all-lowercase ASCII letters and should be one of the top level domain names, such as com, edu, gov, mil, net, or org, or one of the English two-letter codes identifying countries as specified in ISO Standard 3166.

In some cases, the Internet domain name may not be a valid package name. Here are some suggested conventions for dealing with these situations:

The name of a module should correspond to the name of its principal exported package. If a module does not have such a package, or if for legacy reasons it must have a name that does not correspond to one of its exported packages, then its name should still start with the reversed form of an Internet domain with which its author is associated.

Example 6.1-2. Unique Module Names

com.nighthacks.scrabble
org.openjdk.compiler
net.jcip.annotations

The first component of a package or module name must not be the identifier java. Package and module names that start with the identifier java are reserved for packages and modules of the Java SE Platform.

The name of a package or module is not meant to imply where the package or module is stored on the Internet. For example, a package named edu.cmu.cs.bovik.cheese is not necessarily obtainable from the host cmu.edu or cs.cmu.edu or bovik.cs.cmu.edu. The suggested convention for generating unique package and module names is merely a way to piggyback a package and module naming convention on top of an existing, widely known unique name registry instead of having to create a separate registry for package and module names.

Class and Interface Type Names

Names of class types should be descriptive nouns or noun phrases, not overly long, in mixed case with the first letter of each word capitalized.

Example 6.1-3. Descriptive Class Names

`ClassLoader`
SecurityManager
`Thread`
Dictionary
BufferedInputStream

Likewise, names of interface types should be short and descriptive, not overly long, in mixed case with the first letter of each word capitalized. The name may be a descriptive noun or noun phrase, which is appropriate when an interface is used as if it were an abstract superclass, such as interfaces java.io.DataInput and java.io.DataOutput; or it may be an adjective describing a behavior, as for the interfaces Runnable and Cloneable.

Type Variable Names

Type variable names should be pithy (single character if possible) yet evocative, and should not include lower case letters. This makes it easy to distinguish type parameters from ordinary classes and interfaces.

Container types should use the name E for their element type. Maps should use K for the type of their keys and V for the type of their values. The name X should be used for arbitrary exception types. We use T for type, whenever there is not anything more specific about the type to distinguish it. (This is often the case in generic methods.)

If there are multiple type parameters that denote arbitrary types, one should use letters that neighbor T in the alphabet, such as S. Alternately, it is acceptable to use numeric subscripts (e.g., T1, T2) to distinguish among the different type variables. In such cases, all the variables with the same prefix should be subscripted.

If a generic method appears inside a generic class, it is a good idea to avoid using the same names for the type parameters of the method and class, to avoid confusion. The same applies to nested generic classes.

Example 6.1-4. Conventional Type Variable Names

public class HashSet<E> extends AbstractSet<E> { ... }
public class HashMap<K,V> extends AbstractMap<K,V> { ... }
public class ThreadLocal<T> { ... }
public interface Functor<T, X extends Throwable> {
    T eval() throws X;
}

When type parameters do not fall conveniently into one of the categories mentioned, names should be chosen to be as meaningful as possible within the confines of a single letter. The names mentioned above (E, K, V, X, T) should not be used for type parameters that do not fall into the designated categories.

Method Names

Method names should be verbs or verb phrases, in mixed case, with the first letter lowercase and the first letter of any subsequent words capitalized. Here are some additional specific conventions for method names:

Whenever possible and appropriate, basing the names of methods in a new class on names in an existing class that is similar, especially a class from the Java SE Platform API, will make it easier to use.

Field Names

Names of fields that are not final should be in mixed case with a lowercase first letter and the first letters of subsequent words capitalized. Note that well-designed classes have very few public or protected fields, except for fields that are constants (static final fields).

Fields should have names that are nouns, noun phrases, or abbreviations for nouns.

Examples of this convention are the fields buf, pos, and count of the class java.io.ByteArrayInputStream and the field bytesTransferred of the class java.io.InterruptedIOException.

Constant Names

The names of constants in interface types should be, and final variables of class types may conventionally be, a sequence of one or more words, acronyms, or abbreviations, all uppercase, with components separated by underscore "_" characters. Constant names should be descriptive and not unnecessarily abbreviated. Conventionally they may be any appropriate part of speech.

Examples of names for constants include MIN_VALUE, MAX_VALUE, MIN_RADIX, and MAX_RADIX of the class Character.

A group of constants that represent alternative values of a set, or, less frequently, masking bits in an integer value, are sometimes usefully specified with a common acronym as a name prefix.

For example:

interface ProcessStates {
    int PS_RUNNING   = 0;
    int PS_SUSPENDED = 1;
}

Local Variable and Parameter Names

Local variable and parameter names should be short, yet meaningful. They are often short sequences of lowercase letters that are not words, such as:

One-character local variable or parameter names should be avoided, except for temporary and looping variables, or where a variable holds an undistinguished value of a type. Conventional one-character names are:

Local variable or parameter names that consist of only two or three lowercase letters should not conflict with the initial country codes and domain names that are the first component of unique package names.

6.5 Determining the Meaning of a Name

6.5.1 Syntactic Classification of a Name According to Context

A name is syntactically classified as a ModuleName in these contexts:

A name is syntactically classified as a PackageName in these contexts:

A name is syntactically classified as a TypeName in these contexts:

The extraction of a TypeName from the identifiers of a ReferenceType in the 16 contexts above is intended to apply recursively to all sub-terms of the ReferenceType, such as its element type and any type arguments.

For example, suppose a field declaration uses the type p.q.Foo[]. The brackets of the array type are ignored, and the term p.q.Foo is extracted as a dotted sequence of Identifiers to the left of the brackets in an array type, and classified as a TypeName. A later step determines which of p, q, and Foo is a type name or a package name.

As another example, suppose a cast operator uses the type p.q.Foo<? extends String>. The term p.q.Foo is again extracted as a dotted sequence of Identifier terms, this time to the left of the < in a parameterized type, and classified as a TypeName. The term String is extracted as an Identifier in an extends clause of a wildcard type argument of a parameterized type, and classified as a TypeName.

A name is syntactically classified as an ExpressionName in these contexts:

A name is syntactically classified as a MethodName in this context:

A name is syntactically classified as a PackageOrTypeName in these contexts:

A name is syntactically classified as an AmbiguousName in these contexts:

The effect of syntactic classification is to restrict certain kinds of entities to certain parts of expressions:

Chapter 7: Packages and Modules

7.5 Import Declarations

7.5.1 Single-Type-Import Declarations

A single-type-import declaration imports a single type by giving its canonical name, making it available under a simple name in the module, class, and interface declarations of the compilation unit in which the single-type-import declaration appears.

SingleTypeImportDeclaration:
import TypeName ;

The TypeName must be the canonical name of a class type, interface type, enum type, record type, or annotation type (6.7).

The type must be either a member of a named package, or a member of a type whose outermost lexically enclosing type declaration (8.1.3) is a member of a named package, or a compile-time error occurs.

It is a compile-time error if the named type is not accessible (6.6).

If two single-type-import declarations in the same compilation unit attempt to import types with the same simple name, then a compile-time error occurs, unless the two types are the same type, in which case the duplicate declaration is ignored.

If the type imported by the single-type-import declaration is declared in the compilation unit that contains the import declaration, the import declaration is ignored.

If a single-type-import declaration imports a type whose simple name is n, and the compilation unit also declares a top level type (7.6) whose simple name is n, a compile-time error occurs.

If a compilation unit contains both a single-type-import declaration that imports a type whose simple name is n, and a single-static-import declaration (7.5.3) that imports a type whose simple name is n, a compile-time error occurs, unless the two types are the same type, in which case the duplicate declaration is ignored.

Example 7.5.1-1. Single-Type-Import

import java.util.Vector;

causes the simple name Vector to be available within the class and interface declarations in a compilation unit. Thus, the simple name Vector refers to the type declaration Vector in the package java.util in all places where it is not shadowed (6.4.1) or obscured (6.4.2) by a declaration of a field, parameter, local variable, or nested type declaration with the same name.

Note that the actual declaration of java.util.Vector is generic (8.1.2). Once imported, the name Vector can be used without qualification in a parameterized type such as Vector<String>, or as the raw type Vector. A related limitation of the import declaration is that a nested type declared inside a generic type declaration can be imported, but its outer type is always erased.

Example 7.5.1-2. Duplicate Type Declarations

This program:

import java.util.Vector;
class Vector { Object[] vec; }

causes a compile-time error because of the duplicate declaration of Vector, as does:

import java.util.Vector;
import myVector.Vector;

where myVector is a package containing the compilation unit:

package myVector;
public class Vector { Object[] vec; }

Example 7.5.1-3. No Import of a Subpackage

Note that an import declaration cannot import a subpackage, only a type.

For example, it does not work to try to import java.util and then use the name util.Random to refer to the type java.util.Random:

import java.util;
class Test { util.Random generator; }
  // incorrect: compile-time error

Example 7.5.1-4. Importing a Type Name that is also a Package Name

Package names and type names are usually different under the naming conventions described in 6.1. Nevertheless, in a contrived example where there is an unconventionally-named package Vector, which declares a public class whose name is Mosquito:

package Vector;
public class Mosquito { int capacity; }

and then the compilation unit:

package strange;
import java.util.Vector;
import Vector.Mosquito;
class Test {
    public static void main(String[] args) {
        System.out.println(new Vector().getClass());
        System.out.println(new Mosquito().getClass());
    }
}

the single-type-import declaration importing class Vector from package java.util does not prevent the package name Vector from appearing and being correctly recognized in subsequent import declarations. The example compiles and produces the output:

class java.util.Vector
class Vector.Mosquito

7.5.2 Type-Import-on-Demand Declarations

A type-import-on-demand declaration allows all accessible types of a named package or type to be imported as needed.

TypeImportOnDemandDeclaration:
import PackageOrTypeName . * ;

The PackageOrTypeName must be the canonical name (6.7) of a package, a class type, an interface type, an enum type, a record type, or an annotation type.

If the PackageOrTypeName denotes a type (6.5.4), then the type must be either a member of a named package, or a member of a type whose outermost lexically enclosing type declaration (8.1.3) is a member of a named package, or a compile-time error occurs.

It is a compile-time error if the named package is not uniquely visible to the current module (7.4.3), or if the named type is not accessible (6.6).

It is not a compile-time error to name either java.lang or the named package of the current compilation unit in a type-import-on-demand declaration. The type-import-on-demand declaration is ignored in such cases.

Two or more type-import-on-demand declarations in the same compilation unit may name the same type or package. All but one of these declarations are considered redundant; the effect is as if that type was imported only once.

If a compilation unit contains both a type-import-on-demand declaration and a static-import-on-demand declaration (7.5.4) that name the same type, the effect is as if the static member types of that type (8.5, 9.5) were imported only once.

Example 7.5.2-1. Type-Import-on-Demand

import java.util.*;

causes the simple names of all public types declared in the package java.util to be available within the class and interface declarations of the compilation unit. Thus, the simple name Vector refers to the type Vector in the package java.util in all places in the compilation unit where that type declaration is not shadowed (6.4.1) or obscured (6.4.2).

The declaration might be shadowed by a single-type-import declaration of a type whose simple name is Vector; by a type named Vector and declared in the package to which the compilation unit belongs; or any nested classes or interfaces.

The declaration might be obscured by a declaration of a field, parameter, or local variable named Vector.

(It would be unusual for any of these conditions to occur.)

7.5.3 Single-Static-Import Declarations

A single-static-import declaration imports all accessible static members with a given simple name from a type. This makes these static members available under their simple name in the module, class, and interface declarations of the compilation unit in which the single-static-import declaration appears.

SingleStaticImportDeclaration:
import static TypeName . Identifier ;

The TypeName must be the canonical name (6.7) of a class type, interface type, enum type, record type, or annotation type.

The type must be either a member of a named package, or a member of a type whose outermost lexically enclosing type declaration (8.1.3) is a member of a named package, or a compile-time error occurs.

It is a compile-time error if the named type is not accessible (6.6).

The Identifier must name at least one static member of the named type. It is a compile-time error if there is no static member of that name, or if all of the named members are not accessible.

It is permissible for one single-static-import declaration to import several fields or types with the same name, or several methods with the same name and signature. This occurs when the named type inherits multiple fields, member types, or methods, all with the same name, from its own supertypes.

If two single-static-import declarations in the same compilation unit attempt to import types with the same simple name, then a compile-time error occurs, unless the two types are the same type, in which case the duplicate declaration is ignored.

If a single-static-import declaration imports a type whose simple name is n, and the compilation unit also declares a top level type (7.6) whose simple name is n, a compile-time error occurs.

If a compilation unit contains both a single-static-import declaration that imports a type whose simple name is n, and a single-type-import declaration (7.5.1) that imports a type whose simple name is n, a compile-time error occurs, unless the two types are the same type, in which case the duplicate declaration is ignored.

7.5.4 Static-Import-on-Demand Declarations

A static-import-on-demand declaration allows all accessible static members of a named type to be imported as needed.

StaticImportOnDemandDeclaration:
import static TypeName . * ;

The TypeName must be the canonical name (6.7) of a class type, interface type, enum type, record type, or annotation type.

The type must be either a member of a named package, or a member of a type whose outermost lexically enclosing type declaration (8.1.3) is a member of a named package, or a compile-time error occurs.

It is a compile-time error if the named type is not accessible (6.6).

Two or more static-import-on-demand declarations in the same compilation unit may name the same type; the effect is as if there was exactly one such declaration.

Two or more static-import-on-demand declarations in the same compilation unit may name the same member; the effect is as if the member was imported exactly once.

It is permissible for one static-import-on-demand declaration to import several fields or types with the same name, or several methods with the same name and signature. This occurs when the named type inherits multiple fields, member types, or methods, all with the same name, from its own supertypes.

If a compilation unit contains both a static-import-on-demand declaration and a type-import-on-demand declaration (7.5.2) that name the same type, the effect is as if the static member types of that type (8.5, 9.5) were imported only once.

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 and local records (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. A class may be declared final (8.1.1.2), in which case it cannot have 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 three kinds of class declarations: normal class declarations, and enum declarations, and record declarations.

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

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

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

It is a compile-time error if the ClassType names the class Record (8.10).

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.5 Member Type Declarations

8.5.1 Static Member Type Declarations

The static keyword may modify the declaration of a member type C within the body of a non-inner class or interface T. Its effect is to declare that C is not an inner class. Just as a static method of T has no current instance of T in its body, C also has no current instance of T, nor does it have any lexically enclosing instances.

It is a compile-time error if a static class contains a usage of a non-static member of an enclosing class.

A member interface is implicitly static (9.1.1). It is permitted for the declaration of a member interface to redundantly specify the static modifier.

A member record is implicitly static (8.10). It is permitted for the declaration of a member record to redundantly specify the static modifier.

8.8 Constructor Declarations

A constructor is used in the creation of an object that is an instance of a class (12.5, 15.9).

ConstructorDeclaration:
{ConstructorModifier} ConstructorDeclarator [Throws] ConstructorBody
ConstructorDeclarator:
[TypeParameters] SimpleTypeName
( [ReceiverParameter ,] [FormalParameterList] )
SimpleTypeName:
TypeIdentifier

The rules in this section apply to constructors in all class declarations, including enum declarations and record declarations. However, special rules apply to enum declarations with regard to constructor modifiers, constructor bodies, and default constructors; these rules are stated in 8.9.2. Special rules also apply to record declarations with regard to constructors, including a special compact declaration form; the details are given in 8.10.4.

The SimpleTypeName in the ConstructorDeclarator must be the simple name of the class that contains the constructor declaration, or a compile-time error occurs.

In all other respects, a constructor declaration looks just like a method declaration that has no result (8.4.5).

Constructor declarations are not members. They are never inherited and therefore are not subject to hiding or overriding.

Constructors are invoked by class instance creation expressions (15.9), by the conversions and concatenations caused by the string concatenation operator + (15.18.1), and by explicit constructor invocations from other constructors (8.8.7). Access to constructors is governed by access modifiers (6.6), so it is possible to prevent class instantiation by declaring an inaccessible constructor (8.8.10).

Constructors are never invoked by method invocation expressions (15.12).

Example 8.8-1. Constructor Declarations

class Point {
    int x, y;
    Point(int x, int y) { this.x = x; this.y = y; }
}

8.10 Record Types

This is a new section.

A record declaration specifies a new record type, a special kind of class type.

RecordDeclaration:
{ClassModifier} record TypeIdentifier [TypeParameters] RecordHeader [SuperInterfaces] RecordBody

It is a compile-time error if a record declaration has the modifier abstract.

A record declaration is implicitly final. It is permitted for the declaration of a record type to redundantly specify the final modifier.

A nested record type is implicitly static. It is permitted for the declaration of a nested record type to redundantly specify the static modifier.

This implies that it is impossible to declare a record type in the body of an inner class (8.1.3), because an inner class cannot have static members except for constant variables.

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

The direct superclass of a record type R is java.lang.Record.

Note that a record declaration can not explicitly specify a superclass, so it is not possible to explicitly declare that the direct superclass of a record type is java.lang.Record.

The serialization mechanism treats instances of a record type differently to ordinary serializable or externalizable objects. In particular, a record object is deserialized using the canonical constructor (8.10.4).

8.10.1 Record Components

The record components of a record type, if any, are specified by a list of comma-separated parameter specifiers in the header of a record declaration. Each record component consists of a type (optionally preceded by the final modifier and/or one or more annotations) and an identifier (optionally followed by brackets) that specifies the name of the record component. If a record type has no record components, then the record header consists of an empty pair of parentheses.

Each record component corresponds to an implicitly declared field and an accessor method (declared either explicitly or implicitly) of the record type (8.10.3).

RecordHeader:
( [ RecordComponentList ] )
RecordComponentList:
RecordComponent { , RecordComponent }
RecordComponent:
{ VariableModifier } UnannType VariableDeclaratorId
VariableArityRecordComponent
VariableArityRecordComponent:
{ VariableModifier } UnannType { Annotation } ... Identifier

It can be seen that the production for RecordComponent is identical in content to the production for FormalParameter (8.4.1).

The following productions from 8.4.1, 8.3 and 4.3 are shown here for convenience:

FormalParameter:
{ VariableModifier } UnannType VariableDeclaratorId
VariableArityParameter
VariableArityParameter:
{ VariableModifier } UnannType { Annotation } ... Identifier
VariableModifier:
Annotation
final
VariableDeclaratorId:
Identifier [ Dims ]
Dims:
{ Annotation } [ ] { { Annotation } [ ] }

It is permitted for a record component to redundantly specify the final modifier. It is a compile-time error if final appears more than once as a modifier for a record component.

A record component may be a variable arity record component, indicated by an ellipsis following the type. At most one variable arity record component is permitted for a record type. It is a compile-time error if a variable arity record component appears anywhere in the list of record components except the last position.

It is a compile-time error for a record declaration to declare two record components with the same name.

It is a compile-time error for a record declaration to declare a record component with the name clone, finalize, getClass, hashCode, notify, notifyAll, toString, or wait.

As every record component has a corresponding accessor method (8.10.3), this restriction prevents a record type containing possibly illegal overloads of methods from the class Object.

The rules for annotation modifiers on a record component are specified in 9.7.4.

The declared type of a record component depends on whether it is a variable arity record component:

If the declared type of a variable arity record component has a non-reifiable element type (4.7), then a compile-time unchecked warning occurs for the declaration of the variable arity record component, unless the record type is annotated with @SafeVarargs (9.6.4.7) or the warning is suppressed by @SuppressWarnings (9.6.4.5).

8.10.2 Record Bodies

The body of a record declaration may contain constructor and member declarations as well as static initializers.

RecordBody:
{ {RecordBodyDeclaration} }
RecordBodyDeclaration:
ClassBodyDeclaration
CompactConstructorDeclaration

The following productions from 8.1.6 are shown here for convenience:

ClassBodyDeclaration:
ClassMemberDeclaration
InstanceInitializer
StaticInitializer
ConstructorDeclaration
ClassMemberDeclaration:
FieldDeclaration
MethodDeclaration
ClassDeclaration
InterfaceDeclaration
;

It is a compile-time error for the body of a record declaration to contain non-static field declarations (8.3.1.1).

It is a compile-time error for the body of a record declaration to contain a native method declaration (8.4.3.4).

It is a compile-time error for the body of a record declaration to contain an instance initializer (8.6).

8.10.3 Record Members

In a record type R, an accessor method for a record component is a method whose name is the same as the name of the record component of R, and whose formal parameter list is empty.

A record type R has the following members:

If an accessor method is declared explicitly, then it must additionally satisfy the following rules; otherwise a compile-time error occurs:

Annotations that appear on a record component are not carried over to an explicitly declared accessor method for that record component. This is in contrast to an implicitly declared accessor method which is annotated with the applicable annotations from the record component.

All the rules for field declarations and method declarations in a normal class declaration must be satisfied (8.3, 8.4).

8.10.4 Record Constructor Declarations

To support proper initialization of its record components, a record type does not implicitly declare a default constructor (8.8.9). Instead, a record type has a canonical constructor, declared either explicitly or implicitly, that initializes all of the fields corresponding to the record components.

A record type R has a derived constructor signature, with the name R, with no type parameters, and with a formal parameter list that is derived from the record component list of R as follows:

A constructor declared in a record type R is said to be a canonical constructor if its signature is override-equivalent (8.4.2) to the derived constructor signature of R.

As a canonical constructor has a signature that is override-equivalent to the derived constructor signature of a record type, there can only be one explicitly declared canonical constructor.

If a canonical constructor is explicitly declared, then it must additionally satisfy the following conditions; otherwise a compile-time error occurs:

The requirement that the signature of an explicitly declared canonical constructor must be override-equivalent to the derived constructor signature means that the annotations on a record component can differ from the annotations on the corresponding formal parameter. For example, the following is valid:

If the canonical constructor is not explicitly declared, then one is implicitly declared with the following properties:

If a record type R declares constructors whose signatures are not override-equivalent to the derived constructor signature of R, then each constructor (if any) must satisfy all of the following; otherwise a compile-time error occurs:

These requirements enable us to talk of the canonical constructor for a record type R. In other words, every record type R has a single canonical constructor, declared explicitly or implicitly. This canonical constructor has the following properties:

  • It is declared public.
  • It has no throws clause.
  • It is not generic.
  • Its signature is identical to the derived constructor signature of R (excluding any annotations).
  • The constructor body initializes every field corresponding to a record component from the record component list of R.

8.10.5 Compact Record Constructor Declarations

A compact constructor declaration provides an alternative, succinct means to declare a canonical constructor for a record type.

CompactConstructorDeclaration:
{ Annotation } { ConstructorModifier } SimpleTypeName ConstructorBody

In a record type R, the signature of a compact constructor declaration is the derived constructor signature of R (8.10.4).

Unlike constructors in records, and indeed in classes in general, no explicit formal parameter list is given for a compact constructor, but is derived from the record component list.

It is a compile-time error to declare more than one compact constructor declaration for a record type.

The rules concerning signatures of constructors in class declarations (8.8.2) mean that it is also a compile-time error if a record declaration contains a compact constructor declaration and a canonical constructor declaration. A compact constructor is a canonical constructor.

A compact constructor declaration must satisfy all of the following conditions; otherwise a compile-time error occurs.

In addition, at the end of the body of the compact constructor, all the fields corresponding to the record components of R that are definitely unassigned (16 (Definite Assignment)) are implicitly initialized to the value of the corresponding formal parameter. These fields are implicitly initialized in the order that they are declared in the record component list.

The intention of a compact constructor declaration is that only validation and/or normalization code need be given in the constructor body; the remaining initialization code is supplied by the compiler. Here are two simple examples:

These declarations are equivalent to the following:

Chapter 9: Interfaces

9.6 Annotation Types

9.6.4 Predefined Annotation Types

9.6.4.1 @Target

An annotation of type java.lang.annotation.Target is used on the declaration of an annotation type T to specify the contexts in which T is applicable. java.lang.annotation.Target has a single element, value, of type java.lang.annotation.ElementType[], to specify contexts.

Annotation types may be applicable in declaration contexts, where annotations apply to declarations, or in type contexts, where annotations apply to types used in declarations and expressions.

There are nine ten declaration contexts, each corresponding to an enum constant of java.lang.annotation.ElementType:

  1. Module declarations (7.7)

    Corresponds to java.lang.annotation.ElementType.MODULE

  2. Package declarations (7.4.1)

    Corresponds to java.lang.annotation.ElementType.PACKAGE

  3. Type declarations: class, interface, enum, record, and annotation type declarations (8.1.1, 9.1.1, 8.5, 9.5, 8.9, 8.10, 9.6)

    Corresponds to java.lang.annotation.ElementType.TYPE

    Additionally, annotation type declarations correspond to java.lang.annotation.ElementType.ANNOTATION_TYPE

  4. Method declarations (including elements of annotation types) (8.4.3, 9.4, 9.6.1)

    Corresponds to java.lang.annotation.ElementType.METHOD

  5. Constructor declarations (8.8.3)

    Corresponds to java.lang.annotation.ElementType.CONSTRUCTOR

  6. Type parameter declarations of generic classes, interfaces, methods, and constructors (8.1.2, 9.1.2, 8.4.4, 8.8.4)

    Corresponds to java.lang.annotation.ElementType.TYPE_PARAMETER

  7. Field declarations (including enum constants) (8.3.1, 9.3, 8.9.1)

    Corresponds to java.lang.annotation.ElementType.FIELD

  8. Formal and exception parameter declarations (8.4.1, 9.4, 14.20)

    Corresponds to java.lang.annotation.ElementType.PARAMETER

  9. Local variable declarations (including loop variables of for statements and resource variables of try-with-resources statements) (14.4, 14.14.1, 14.14.2, 14.20.3)

    Corresponds to java.lang.annotation.ElementType.LOCAL_VARIABLE

  10. Record component declarations (8.10.1)

    Corresponds to java.lang.annotation.ElementType.RECORD_COMPONENT

There are 16 17 type contexts (4.11), all represented by the enum constant TYPE_USE of java.lang.annotation.ElementType.

It is a compile-time error if the same enum constant appears more than once in the value element of an annotation of type java.lang.annotation.Target.

If an annotation of type java.lang.annotation.Target is not present on the declaration of an annotation type T, then T is applicable in all declaration contexts except type parameter declarations, and in no type contexts.

These contexts are the syntactic locations where annotations were allowed in Java SE 7.

9.7 Annotations

9.7.4 Where Annotations May Appear

A declaration annotation is an annotation that applies to a declaration, and whose own type is applicable in the declaration context (9.6.4.1) represented by that declaration; or an annotation that applies to a class, interface, enum, record, annotation type, or type parameter declaration, and whose own type is applicable in type contexts (4.11).

A type annotation is an annotation that applies to a type (or any part of a type), and whose own type is applicable in type contexts.

For example, given the field declaration:

@Foo int f;

@Foo is a declaration annotation on f if Foo is meta-annotated by @Target(ElementType.FIELD), and a type annotation on int if Foo is meta-annotated by @Target(ElementType.TYPE_USE). It is possible for @Foo to be both a declaration annotation and a type annotation simultaneously.

Type annotations can apply to an array type or any component type thereof (10.1). For example, assuming that A, B, and C are annotation types meta-annotated with @Target(ElementType.TYPE_USE), then given the field declaration:

@C int @A [] @B [] f;

@A applies to the array type int[][], @B applies to its component type int[], and @C applies to the element type int. For more examples, see 10.2.

An important property of this syntax is that, in two declarations that differ only in the number of array levels, the annotations to the left of the type refer to the same type. For example, @C applies to the type int in all of the following declarations:

@C int f;
@C int[] f;
@C int[][] f;

It is customary, though not required, to write declaration annotations before all other modifiers, and type annotations immediately before the type to which they apply.

It is possible for an annotation to appear at a syntactic location in a program where it could plausibly apply to a declaration, or a type, or both. This can happen in any of the five six declaration contexts where modifiers immediately precede the type of the declared entity:

The grammar of the Java programming language unambiguously treats annotations at these locations as modifiers for a declaration (8.3), but that is purely a syntactic matter. Whether an annotation applies to the declaration or to the type of the declared entity - and thus, whether the annotation is a declaration annotation or a type annotation - depends on the applicability of the annotation's type:

In the second and third cases above, the type which is closest to the annotation is determined as follows:

It is a compile-time error if an annotation of type T is syntactically a modifier for:

Five Six of these nine eleven clauses mention "... or type contexts"because they characterize the five six syntactic locations where an annotation could plausibly apply either to a declaration or to the type of a declared entity. Furthermore, two of the nine eleven clauses - for class, interface, enum, record, and annotation type declarations, and for type parameter declarations - mention "... or type contexts" because it may be convenient to apply an annotation whose type is meta-annotated with @Target(ElementType.TYPE_USE) (thus, applicable in type contexts) to a type declaration.

A type annotation is admissible if both of the following are true:

The intuition behind the second clause is that if Outer.this is legal in a nested class enclosed by Outer, then Outer may be annotated because it represents the type of some object at run time. On the other hand, if Outer.this is not legal - because the class where it appears has no enclosing instance of Outer at run time - then Outer may not be annotated because it is logically just a name, akin to components of a package name in a fully qualified type name.

For example, in the following program, it is not possible to write A.this in the body of B, as B has no lexically enclosing instances (8.5.1). Therefore, it is not possible to apply @Foo to A in the type A.B, because A is logically just a name, not a type.

@Target(ElementType.TYPE_USE)
@interface Foo {}

class Test {
  class A {
    static class B {}
  }

  @Foo A.B x;  // Illegal
}

On the other hand, in the following program, it is possible to write C.this in the body of D. Therefore, it is possible to apply @Foo to C in the type C.D, because C represents the type of some object at run time.

@Target(ElementType.TYPE_USE)
@interface Foo {}

class Test {
  static class C {
    class D {}
  }

  @Foo C.D x;  // Legal
}

Finally, note that the second clause looks only one level deeper in a qualified type. This is because a static class may only be nested in a top level class or another static nested class. It is not possible to write a nest like:

@Target(ElementType.TYPE_USE)
@interface Foo {}

class Test {
  class E {
    class F {
      static class G {}
    }
  }

  @Foo E.F.G x;
}

Assume for a moment that the nest was legal. In the type of field x, E and F would logically be names qualifying G, as E.F.this would be illegal in the body of G. Then, @Foo should not be legal next to E. Technically, however, @Foo would be admissible next to E because the next deepest term F denotes an inner class; but this is moot as the class nest is illegal in the first place.

It is a compile-time error if an annotation of type T applies to the outermost level of a type in a type context, and T is not applicable in type contexts or the declaration context (if any) which occupies the same syntactic location.

It is a compile-time error if an annotation of type T applies to a part of a type (that is, not the outermost level) in a type context, and T is not applicable in type contexts.

It is a compile-time error if an annotation of type T applies to a type (or any part of a type) in a type context, and T is applicable in type contexts, and the annotation is not admissible.

For example, assume an annotation type TA which is meta-annotated with just @Target(ElementType.TYPE_USE). The terms @TA java.lang.Object and java.@TA lang.Object are illegal because the simple name to which @TA is closest is classified as a package name. On the other hand, java.lang.@TA Object is legal.

Note that the illegal terms are illegal "everywhere". The ban on annotating package names applies broadly: to locations which are solely type contexts, such as class ... extends @TA java.lang.Object {...}, and to locations which are both declaration and type contexts, such as @TA java.lang.Object f;. (There are no locations which are solely declaration contexts where a package name could be annotated, as class, package, and type parameter declarations use only simple names.)

If TA is additionally meta-annotated with @Target(ElementType.FIELD), then the term @TA java.lang.Object is legal in locations which are both declaration and type contexts, such as a field declaration @TA java.lang.Object f;. Here, @TA is deemed to apply to the declaration of f (and not to the type java.lang.Object) because TA is applicable in the field declaration context.

Chapter 10: Arrays

10.2 Array Variables

A variable of array type holds a reference to an object. Declaring a variable of array type does not create an array object or allocate any space for array components. It creates only the variable itself, which can contain a reference to an array. However, the initializer part of a declarator (8.3, 9.3, 14.4.1) may create an array, a reference to which then becomes the initial value of the variable.

Example 10.2-1. Declarations of Array Variables

int[]     ai;        // array of int
short[][] as;        // array of array of short
short     s,         // scalar short
          aas[][];   // array of array of short
Object[]  ao,        // array of Object
          otherAo;   // array of Object
Collection<?>[] ca;  // array of Collection of unknown type

The declarations above do not create array objects. The following are examples of declarations of array variables that do create array objects:

Exception ae[]  = new Exception[3];
Object aao[][]  = new Exception[2][3];
int[] factorial = { 1, 1, 2, 6, 24, 120, 720, 5040 };
char ac[]       = { 'n', 'o', 't', ' ', 'a', ' ',
                    'S', 't', 'r', 'i', 'n', 'g' };
String[] aas    = { "array", "of", "String", };

The array type of a variable depends on the bracket pairs that may appear as part of the type at the beginning of a variable declaration, or as part of the declarator for the variable, or both. Specifically, in the declaration of a field, formal parameter, or local variable, or record component (8.3, 8.4.1, 9.3, 9.4, 14.4.1, 14.14.2, 15.27.1, 8.10.1), the array type of the variable is denoted by:

The return type of a method (8.4.5) may be an array type. The precise array type depends on the bracket pairs that may appear as part of the type at the beginning of the method declaration, or after the method's formal parameter list, or both. The array type is denoted by:

We do not recommend "mixed notation" in array variable declarations, where bracket pairs appear on both the type and in declarators; nor in method declarations, where bracket pairs appear both before and after the formal parameter list.

Example 10.2-2. Array Variables and Array Types

The local variable declaration statement:

byte[] rowvector, colvector, matrix[];

is equivalent to:

byte rowvector[], colvector[], matrix[][];

because the array type of each local variable is unchanged. Similarly, the local variable declaration statement:

int a, b[], c[][];

is equivalent to the series of declaration statements:

int a;
int[] b;
int[][] c;

Brackets are allowed in declarators as a nod to the tradition of C and C++. The general rules for variable declaration, however, permit brackets to appear on both the type and in declarators, so that the local variable declaration statement:

float[][] f[][], g[][][], h[];  // Yechh!

is equivalent to the series of declarations:

float[][][][] f;
float[][][][][] g;
float[][][] h;

Because of how array types are formed, the following parameter declarations have the same array type:

void m(int @A [] @B []  x) {}
void n(int @A [] @B ... y) {}

And perhaps surprisingly, the following field declarations have the same array type:

int @A [] f @B [];
int @B [] @A [] g;

Once an array object is created, its length never changes. To make an array variable refer to an array of different length, a reference to a different array must be assigned to the variable.

A single variable of array type may contain references to arrays of different lengths, because an array's length is not part of its type.

If an array variable v has type A[], where A is a reference type, then v can hold a reference to an instance of any array type B[], provided B can be assigned to A (5.2). This may result in a run-time exception on a later assignment; see 10.5 for a discussion.

Chapter 13: Binary Compatibility

A companion document describes the changes needed to the Java Virtual Machine Specification to support records.

13.1 The Form of a Binary

Programs must be compiled either into the class file format specified by The Java Virtual Machine Specification, Java SE 13 Edition, or into a representation that can be mapped into that format by a class loader written in the Java programming language.

A class file corresponding to a class or interface declaration must have certain properties. A number of these properties are specifically chosen to support source code transformations that preserve binary compatibility. The required properties are:

  1. The class or interface must be named by its binary name, which must meet the following constraints:

    • The binary name of a top level type (7.6) is its canonical name (6.7).

    • The binary name of a member type (8.5, 9.5) consists of the binary name of its immediately enclosing type, followed by $, followed by the simple name of the member.

    • The binary name of a local class (14.3) consists of the binary name of its immediately enclosing type, followed by $, followed by a non-empty sequence of digits, followed by the simple name of the local class.

    • The binary name of an anonymous class (15.9.5) consists of the binary name of its immediately enclosing type, followed by $, followed by a non-empty sequence of digits.

    • The binary name of a type variable declared by a generic class or interface (8.1.2, 9.1.2) is the binary name of its immediately enclosing type, followed by $, followed by the simple name of the type variable.

    • The binary name of a type variable declared by a generic method (8.4.4) is the binary name of the type declaring the method, followed by $, followed by the descriptor of the method (JVMS §4.3.3), followed by $, followed by the simple name of the type variable.

    • The binary name of a type variable declared by a generic constructor (8.8.4) is the binary name of the type declaring the constructor, followed by $, followed by the descriptor of the constructor (JVMS §4.3.3), followed by $, followed by the simple name of the type variable.

  2. A reference to another class or interface type must be symbolic, using the binary name of the type.

  3. A reference to a field that is a constant variable (4.12.4) must be resolved at compile time to the value V denoted by the constant variable's initializer.

    If such a field is static, then no reference to the field should be present in the code in a binary file, including the class or interface which declared the field. Such a field must always appear to have been initialized (12.4.2); the default initial value for the field (if different than V) must never be observed.

    If such a field is non-static, then no reference to the field should be present in the code in a binary file, except in the class containing the field. (It will be a class rather than an interface, since an interface has only static fields.) The class should have code to set the field's value to V during instance creation (12.5).

  4. Given a legal expression denoting a field access in a class C, referencing a field named f that is not a constant variable and is declared in a (possibly distinct) class or interface D, we define the qualifying type of the field reference as follows:

    • If the expression is referenced by a simple name, then if f is a member of the current class or interface, C, then let T be C. Otherwise, let T be the innermost lexically enclosing type declaration of which f is a member. In either case, T is the qualifying type of the reference.

    • If the reference is of the form TypeName.f, where TypeName denotes a class or interface, then the class or interface denoted by TypeName is the qualifying type of the reference.

    • If the expression is of the form ExpressionName.f or Primary.f, then:

      • If the compile-time type of ExpressionName or Primary is an intersection type V1 & ... & Vn (4.9), then the qualifying type of the reference is V1.

      • Otherwise, the compile-time type of ExpressionName or Primary is the qualifying type of the reference.

    • If the expression is of the form super.f, then the superclass of C is the qualifying type of the reference.

    • If the expression is of the form TypeName.super.f, then the superclass of the class denoted by TypeName is the qualifying type of the reference.

    The reference to f must be compiled into a symbolic reference to the erasure (4.6) of the qualifying type of the reference, plus the simple name of the field, f. The reference must also include a symbolic reference to the erasure of the declared type of the field so that the verifier can check that the type is as expected.

  5. Given a method invocation expression or a method reference expression in a class or interface C, referencing a method named m declared (or implicitly declared (9.2)) in a (possibly distinct) class or interface D, we define the qualifying type of the method invocation as follows:

    • If D is Object then the qualifying type of the expression is Object.

    • Otherwise:

      • If the method is referenced by a simple name, then if m is a member of the current class or interface C, let T be C; otherwise, let T be the innermost lexically enclosing type declaration of which m is a member. In either case, T is the qualifying type of the method invocation.

      • If the expression is of the form TypeName.m or ReferenceType::m, then the type denoted by TypeName or ReferenceType is the qualifying type of the method invocation.

      • If the expression is of the form ExpressionName.m or Primary.m or ExpressionName::m or Primary::m, then:

        • If the compile-time type of ExpressionName or Primary is an intersection type V1 & ... & Vn (4.9), then the qualifying type of the method invocation is V1.

        • Otherwise, the compile-time type of ExpressionName or Primary is the qualifying type of the method invocation.

      • If the expression is of the form super.m or super::m, then the superclass of C is the qualifying type of the method invocation.

      • If the expression is of the form TypeName.super.m or TypeName.super::m, then if TypeName denotes a class X, the superclass of X is the qualifying type of the method invocation; if TypeName denotes an interface X, X is the qualifying type of the method invocation.

    A reference to a method must be resolved at compile time to a symbolic reference to the erasure (4.6) of the qualifying type of the invocation, plus the erasure of the signature (8.4.2) of the method. The signature of a method must include all of the following as determined by 15.12.3:

    • The simple name of the method

    • The number of parameters to the method

    • A symbolic reference to the type of each parameter

    A reference to a method must also include either a symbolic reference to the erasure of the return type of the denoted method or an indication that the denoted method is declared void and does not return a value.

  6. Given a class instance creation expression (15.9) or an explicit constructor invocation statement (8.8.7.1) or a method reference expression of the form ClassType :: new (15.13) in a class or interface C referencing a constructor m declared in a (possibly distinct) class or interface D, we define the qualifying type of the constructor invocation as follows:

    • If the expression is of the form new D(...) or ExpressionName.new D(...) or Primary.new D(...) or D :: new, then the qualifying type of the invocation is D.

    • If the expression is of the form new D(...){...} or ExpressionName.new D(...){...} or Primary.new D(...){...}, then the qualifying type of the expression is the compile-time type of the expression.

    • If the expression is of the form super(...) or ExpressionName.super(...) or Primary.super(...), then the qualifying type of the expression is the direct superclass of C.

    • If the expression is of the form this(...), then the qualifying type of the expression is C.

    A reference to a constructor must be resolved at compile time to a symbolic reference to the erasure (4.6) of the qualifying type of the invocation, plus the signature of the constructor (8.8.2). The signature of a constructor must include both:

    • The number of parameters of the constructor

    • A symbolic reference to the type of each formal parameter

A binary representation for a class or interface must also contain all of the following:

  1. If it is a class and is not Object, then a symbolic reference to the erasure of the direct superclass of this class.

  2. A symbolic reference to the erasure of each direct superinterface, if any.

  3. A specification of each field declared in the class or interface, given as the simple name of the field and a symbolic reference to the erasure of the type of the field.

  4. If it is a class, then the erased signature of each constructor, as described above.

  5. For each method declared in the class or interface (excluding, for an interface, its implicitly declared methods (9.2)), its erased signature and return type, as described above.

  6. The code needed to implement the class or interface:

    • For an interface, code for the field initializers and the implementation of each method with a block body (9.4.3).

    • For a class, code for the field initializers, the instance and static initializers, the implementation of each method with a block body (8.4.7), and the implementation of each constructor.

  7. Every type must contain sufficient information to recover its canonical name (6.7).

  8. Every member type must have sufficient information to recover its source-level access modifier.

  9. Every nested class and nested interface must have a symbolic reference to its immediately enclosing type (8.1.3).

  10. Every class must contain symbolic references to all of its member types (8.5), and to all local and anonymous classes that appear in its methods, constructors, static initializers, instance initializers, and field initializers.

    Every interface must contain symbolic references to all of its member types (9.5), and to all local and anonymous classes that appear in its default methods and field initializers.

  11. A construct emitted by a Java compiler must be marked as synthetic if it does not correspond to a construct declared explicitly or implicitly in source code, unless the emitted construct is a class initialization method (JVMS §2.9).

  12. A construct emitted by a Java compiler must be marked as mandated if it corresponds to a formal parameter declared implicitly in source code (8.8.1, 8.8.9, 8.9.3, 15.9.5.1).

The following formal parameters are declared implicitly in source code:

For reference, the following constructs are declared implicitly in source code, but are not marked as mandated because only formal parameters can be so marked in a class file (JVMS §4.7.24):

A class file corresponding to a module declaration must have the properties of a class file for a class whose binary name is module-info and which has no superclass, no superinterfaces, no fields, and no methods. In addition, the binary representation of the module must contain all of the following:

The following sections discuss changes that may be made to class and interface type declarations without breaking compatibility with pre-existing binaries. Under the translation requirements given above, the Java Virtual Machine and its class file format support these changes. Any other valid binary format, such as a compressed or encrypted representation that is mapped back into class files by a class loader under the above requirements, will necessarily support these changes as well.

13.4 Evolution of Classes

13.4.27 Evolution of Records

This is a new subsection

Adding, deleting, changing, or reordering record components in a record declaration may break compatibility with pre-existing binaries, resulting in a linkage time error, namely an IncompatibleClassChangeError.

If a pre-existing binary attempts to access a record component that no longer exists, the client will fail at run time with a NoSuchFieldError. Therefore such a change is not recommended for widely distributed records.

In all other respects, the binary compatibility rules for records are identical to those for classes.

Chapter 14: Blocks and Statements

14.2 Blocks

A block is a sequence of statements, local class declarations, and local variable declaration statements within braces.

A block is a sequence of statements and declarations within braces. Local variable declaration statements are an important kind of statement because they introduce names into scope. The declarations that appear in a block may be of classes and records (but not enums); these declarations are known as local classes and local records.

Block:
{ [BlockStatements] }
BlockStatements:
BlockStatement {BlockStatement}
BlockStatement:
LocalVariableDeclarationStatement
ClassDeclaration NormalClassDeclaration
RecordDeclaration
Statement

A block is executed by executing each of the local variable declaration statements and other statements in order from first to last (left to right). If all of these block statements complete normally, then the block completes normally. If any of these block statements complete abruptly for any reason, then the block completes abruptly for the same reason.

14.3 Local Class Declarations

A local class declaration is the declaration of either a local class or a local record (but not an enum).

A local class is a nested class (8) that is not a member of any class and that has a name (6.2, 6.7).

All local classes are inner classes (8.1.3).

A local record is a record type declaration (8.10) that is not a member of a class. A local record is implicitly static.

Every local class declaration statement is immediately contained by a block (14.2). Local class declaration statements may be intermixed freely with other kinds of statements in the block.

It is a compile-time error if a local class declaration contains any of the access modifiers public, protected, or private (6.6), or, if it is not a local record, the modifier static (8.1.1).

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

Example 14.3-1. Local Class Declarations

Here is an example that illustrates several aspects of the rules given above:

class Global {
    class Cyclic {}

    void foo() {
        new Cyclic(); // create a Global.Cyclic
        class Cyclic extends Cyclic {} // circular definition

        {
            class Local {}
            {
                class Local {} // compile-time error
            }
            class Local {} // compile-time error
            class AnotherLocal {
                void bar() {
                    class Local {} // ok
                }
            }
        }
        class Local {} // ok, not in scope of prior Local
    }
}

The first statement of method foo creates an instance of the member class Global.Cyclic rather than an instance of the local class Cyclic, because the statement appears prior to the scope of the local class declaration.

The fact that the scope of a local class declaration encompasses its whole declaration (not only its body) means that the definition of the local class Cyclic is indeed cyclic because it extends itself rather than Global.Cyclic. Consequently, the declaration of the local class Cyclic is rejected at compile time.

Since local class names cannot be redeclared within the same method (or constructor or initializer, as the case may be), the second and third declarations of Local result in compile-time errors. However, Local can be redeclared in the context of another, more deeply nested, class such as AnotherLocal.

The final declaration of Local is legal, since it occurs outside the scope of any prior declaration of Local.