This document describes changes to the Java Language Specification to support value classes and objects, a preview feature introduced by JEP 401.
Key changes include:
Value objects as a new kind of object, with special behaviors for instantiation,
==, and synchronizationA new
valuecontext-sensitive keyword for use as a class modifier, with special restrictions applied to value class declarationsEarly execution of value class and record class constructors, except where an explicit constructor invocation is used; support for field reads during early construction
Changes are described with respect to existing sections of the JVM
Specification. New text is indicated like this and
deleted text is indicated like this. Explanation and
discussion, as needed, is set aside in grey boxes.
Revision history:
February 2026: rebased to JLS 26
December 2025: fixed up rules related to field references in early construction contexts (6.5.6.1, 15.8.3, 15.8.4, 16)
September 2025: introduced statewise equivalence as a term to explain
==(15.21.3); applied early construction rules to record constructors (8.8.7, 8.10.4.1, 8.10.4.2); revised rules for field references in early construction (6.5.6.1); tightened memory model for value class and record fields (17.5.1, 17.5.3); clarified the treatment of field initializers (8.3.2)November 2024: addressed handling of value classes in the standard libraries, including the behavior of boxing (5.1.7); prohibited using
sealedandnon-sealedwith non-abstractvalue classes; removed unnecessarily extra rules about forward references to fields (8.3.3); refined binary compatibility rules (13.4.1); added some clarifying notesJune 2024: changed the exception type of a failed
synchronizedstatement toIdentityExceptionJanuary 2024: dropped the
identitykeyword and adopted a simplified approach where all classes are considered identity classes by default; switched to a construction scheme building on Statements beforesuper(...).May 2023: revised the definition of "the same" for value objects with
floatanddoublefields (4.3.1)August 2022: fixed rules about
synchronizedmethods (8.1.1.5, 8.4.3.6) and binary compatibility ofidentity/valueclasses (13.4.1)May 2022: clarified that
identityconstrains the subclasses of a concrete class (8.1.1.5); added rules aboutabstractinner classes (8.1.3) andabstractclasses with instance initializers (8.6) or constructors (8.8)April 2022: initial draft
Chapter 3: Lexical Structure
3.8 Identifiers
...
To facilitate the recognition of contextual keywords, the syntactic grammar (2.3) sometimes disallows certain identifiers by defining a production to accept only a subset of identifiers. The subsets are as follows:
- TypeIdentifier:
-
Identifier but not
permits,record,sealed, -
value,var, oryield - UnqualifiedMethodIdentifier:
-
Identifier but not
yield
TypeIdentifier is used in the declaration of classes, interfaces, and type parameters (8.1, 9.1, 4.4), and when referring to types (6.5). For example, the name of a class must be a TypeIdentifier, so it is illegal to declare a class named
permits,record,sealed,value,var, oryield.
UnqualifiedMethodIdentifier is used when a method invocation expression refers to a method by its simple name (6.5.7.1). Since the term
yieldis excluded from UnqualifiedMethodIdentifier, any invocation of a method namedyieldmust be qualified, thus distinguishing the invocation from ayieldstatement (14.21).
For the purpose of parsing, modifiers in class headers don't actually
conflict with types, and so it would be possible to to recognize the
value keyword (along with sealed) without
disallowing it as a class name.
However, it's potentially convenient to be able to implement a single
keyword recognition algorithm for modifiers on all
declarations, and in that approach it's impossible to distinguish
between a constructor declaration or a method declaration spelled
value foo() {} (that is, unless the algorithm is willing to
rely on name resolution to decide whether foo is the
current class name). So we've tentatively added value to
the list of names excluded from TypeIdentifier.
3.9 Keywords
51 character sequences, formed from
ASCII characters, are reserved for use as keywords and cannot be used as
identifiers (3.8). Another 17
18 character sequences, also formed from ASCII
characters, may be interpreted as keywords or as other tokens, depending
on the context in which they appear.
- Keyword:
- ReservedKeyword
- ContextualKeyword
- ReservedKeyword:
- (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) - ContextualKeyword:
- (one of)
-
exports opens requires uses yield
module permits sealed var
non-sealed provides to when
open record transitive with
value
The keywords
constandgotoare 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.
The keyword
strictfpis obsolete and should not be used in new code.
The keyword
_(underscore) may be used in certain declarations in place of an identifier (6.1).
trueandfalseare not keywords, but rather boolean literals (3.10.3).
nullis not a keyword, but rather the null literal (3.10.8).
During the reduction of input characters to input elements (3.5), a sequence of input characters that notionally matches a contextual keyword is reduced to a contextual keyword if and only if both of the following conditions hold:
The sequence is recognized as a terminal specified in a suitable context of the syntactic grammar (2.3), as follows:
For
module, when recognized as a terminal in a SingleModuleImportDeclaration (7.5.5), or a ModuleDeclaration (7.7).For
open, when recognized as a terminal in a ModuleDeclaration (7.7).For
exports,opens,provides,requires,to,uses, andwith, when recognized as a terminal in a ModuleDirective.For
transitive, when recognized as a terminal in a RequiresModifier.For example, recognizing the sequence
requirestransitive;does not make use of RequiresModifier, so the termtransitiveis reduced here to an identifier and not a contextual keyword.For
var, when recognized as a terminal in a LocalVariableType (14.4) or a LambdaParameterType (15.27.1).In other contexts, attempting to use
varas an identifier will cause an error, becausevaris not a TypeIdentifier (3.8).For
yield, when recognized as a terminal in a YieldStatement (14.21).In other contexts, attempting to use the
yieldas an identifier will cause an error, becauseyieldis neither a TypeIdentifier nor a UnqualifiedMethodIdentifier.For
record, when recognized as a terminal in a RecordDeclaration (8.10).For
permits, when recognized as a terminal in a ClassPermits (8.1.6) or an InterfacePermits (9.1.4).For
non-sealed,andpermits,sealed, when recognized as aterminalClassModifier or InterfaceModifier in a NormalClassDeclaration (8.1), EnumDeclaration (8.9), RecordDeclaration (8.10),or aNormalInterfaceDeclaration (9.1), or AnnotationInterfaceDeclaration (9.6).For
when, when recognized as a terminal in a Guard (14.11.1).For
value, when recognized as a ClassModifier in a NormalClassDeclaration, EnumDeclaration, or RecordDeclaration.
Some combinations of modifiers and declarations don't make sense, like a
value enum. However, these are semantic restrictions that should not affect parsing.The sequence is not immediately preceded or immediately followed by an input character that matches JavaLetterOrDigit.
In general, accidentally omitting white space in source code will cause a sequence of input characters to be tokenized as an identifier, due to the "longest possible translation" rule (3.2). For example, the sequence of twelve input characters
p u b l i c s t a t i cis always tokenized as the identifierpublicstatic, rather than as the reserved keywordspublicandstatic. If two tokens are intended, they must be separated by white space or a comment.
The rule above works in tandem with the "longest possible translation" rule to produce an intuitive result in contexts where contextual keywords may appear. For example, the sequence of eleven input characters
v a r f i l e n a m eis usually tokenized as the identifiervarfilename, but in a local variable declaration, the first three input characters are tentatively recognized as the contextual keywordvarby the first condition of the rule above. However, it would be confusing to overlook the lack of white space in the sequence by recognizing the next eight input characters as the identifierfilename. (This would mean that the sequence undergoes different tokenization in different contexts: an identifier in most contexts, but a contextual keyword and an identifier in local variable declarations.) Accordingly, the second condition prevents recognition of the contextual keywordvaron the grounds that the immediately following input characterfis a JavaLetterOrDigit. The sequencev a r f i l e n a m eis therefore tokenized as the identifiervarfilenamein a local variable declaration.
As another example of the careful recognition of contextual keywords, consider the sequence of 15 input characters
n o n - s e a l e d c l a s s. This sequence is usually translated to three tokens - the identifiernon, the operator-, and the identifiersealedclass- but in a normal class declaration, where the first condition holds, the first ten input characters are tentatively recognized as the contextual keywordnon-sealed. To avoid translating the sequence to two keyword tokens (non-sealedandclass) rather than three non-keyword tokens, and to avoid rewarding the programmer for omitting white space beforeclass, the second condition prevents recognition of the contextual keyword. The sequencen o n - s e a l e d c l a s sis therefore tokenized as three tokens in a class declaration.
In the rule above, the first condition depends on details of the syntactic grammar, but a compiler for the Java programming language can implement the rule without fully parsing the input program. For example, a heuristic could be used to track the contextual state of the tokenizer, as long as the heuristic guarantees that valid uses of contextual keywords are tokenized as keywords, and valid uses of identifiers are tokenized as identifiers. Alternatively, a compiler could always tokenize a contextual keyword as an identifier, leaving it to a later phase to recognize special uses of these identifiers.
Chapter 4: Types, Values, and Variables
4.3 Reference Types and Values
4.3.1 Objects
An object is a class instance or an array. A class instance may be an identity object or a value object; every array is an identity object.
The reference values (often
just references) are pointers to these objects, and a special
null reference, which refers to no object.
A class instance is explicitly created by a class instance creation expression (15.9).
An array is explicitly created by an array creation expression (15.10.1).
Other expressions may implicitly create a class instance (12.5) or an array (10.6).
Creation of an identity object produces a unique object, distinct from any that has previously been created. Creation of a value object may result in an object that is indistinguishable from a previously-created object.
Example 4.3.1-1. Object Creation
class Point {
int x, y;
Point() { System.out.println("default"); }
Point(int x, int y) { this.x = x; this.y = y; }
/* A Point instance is explicitly created at
class initialization time: */
static Point origin = new Point(0,0);
/* A String can be implicitly created
by a + operator: */
public String toString() { return "(" + x + "," + y + ")"; }
}
class Test {
public static void main(String[] args) {
/* A Point is explicitly created
using newInstance: */
Point p = null;
try {
p = (Point)Class.forName("Point").newInstance();
} catch (Exception e) {
System.out.println(e);
}
/* An array is implicitly created
by an array initializer: */
Point[] a = { new Point(0,0), new Point(1,1) };
/* Strings are implicitly created
by + operators: */
System.out.println("p: " + p);
System.out.println("a: { " + a[0] + ", " + a[1] + " }");
/* An array is explicitly created
by an array creation expression: */
String[] sa = new String[2];
sa[0] = "he"; sa[1] = "llo";
System.out.println(sa[0] + sa[1]);
}
}
This program produces the output:
default
p: (0,0)
a: { (0,0), (1,1) }
hello
Programs work with objects via reference values. Reference values (often just references) refer to objects, or may be the special null reference, which refers to no object.
The operators on references to objects are:
Field access, using either a qualified name (6.6) or a field access expression (15.11)
Method invocation (15.12)
The string concatenation operator
+(15.18.1), which, when given aStringoperand and a reference, will convert the reference to aStringby invoking thetoStringmethod of the referenced object (using"null"if either the reference or the result oftoStringis a null reference), and then will produce a newly createdStringthat is the concatenation of the two stringsThe
instanceofoperator (15.20.2)The
referenceobject equality operators==and!=(15.21.3)The conditional operator
? :(15.25).
There may be many references to the
same object. Most objects Identity objects
often have mutable state, stored in the fields
of objects that are instances of classes or in the variables that are
the components of an array object. If two variables contain references
to the same identity object, the state of the object
can be modified using one variable's reference to the object, and then
the altered state can be observed through the reference in the other
variable.
Example 4.3.1-2. Primitive and Reference Identity
class Value { int val; }
class Test {
public static void main(String[] args) {
int i1 = 3;
int i2 = i1;
i2 = 4;
System.out.print("i1==" + i1);
System.out.println(" but i2==" + i2);
Value v1 = new Value();
v1.val = 5;
Value v2 = v1;
v2.val = 6;
System.out.print("v1.val==" + v1.val);
System.out.println(" and v2.val==" + v2.val);
}
}
This program produces the output:
i1==3 but i2==4
v1.val==6 and v2.val==6
because v1.val and v2.val reference the
same instance variable (4.12.3)
in the one Value object created by the only
new expression, while i1 and i2
are different variables.
These examples need to be updated.
There are a lot of problems in this second example that will need to be cleaned up. For example, the word "value" is confusing here.
Each identity
object is associated with a monitor (17.1),
which is used by synchronized methods (8.4.3) and the
synchronized statement (14.19) to
provide control over concurrent access to state by multiple threads (17).
Chapter 5: Conversions and Contexts
5.1 Kinds of Conversion
5.1.7 Boxing Conversion
Boxing conversion treats expressions of a primitive type as expressions of a corresponding reference type. Specifically, the following nine conversions are called the boxing conversions:
From type
booleanto typeBooleanFrom type
byteto typeByteFrom type
shortto typeShortFrom type
charto typeCharacterFrom type
intto typeIntegerFrom type
longto typeLongFrom type
floatto typeFloatFrom type
doubleto typeDoubleFrom the null type to the null type
This rule is necessary because the conditional operator (15.25) applies boxing conversion to the types of its operands, and uses the result in further calculations.
At run time, boxing conversion proceeds as follows:
If p is a value of type
boolean, then boxing conversion converts p into a reference r of class and typeBoolean, such thatr.booleanValue() == pIf p is a value of type
byte, then boxing conversion converts p into a reference r of class and typeByte, such thatr.byteValue() == pIf p is a value of type
char, then boxing conversion converts p into a reference r of class and typeCharacter, such thatr.charValue() == pIf p is a value of type
short, then boxing conversion converts p into a reference r of class and typeShort, such thatr.shortValue() == pIf p is a value of type
int, then boxing conversion converts p into a reference r of class and typeInteger, such thatr.intValue() == pIf p is a value of type
long, then boxing conversion converts p into a reference r of class and typeLong, such thatr.longValue() == pIf p is a value of type
floatthen:If p is not NaN, then boxing conversion converts p into a reference r of class and type
Float, such thatr.floatValue()evaluates to pOtherwise, boxing conversion converts p into a reference r of class and type
Floatsuch thatr.isNaN()evaluates totrue
If p is a value of type
double, then:If p is not NaN, boxing conversion converts p into a reference r of class and type
Double, such thatr.doubleValue()evaluates to pOtherwise, boxing conversion converts p into a reference r of class and type
Doublesuch thatr.isNaN()evaluates totrue
If p is a value of any other type, boxing conversion is equivalent to an identity conversion (5.1.1).
If the value p being boxed
is the result of evaluating a constant expression (15.29) of type
boolean, byte, char,
short, int, or long, and the
result is true, false, a character in the
range '\u0000' to '\u007f' inclusive, or an
integer in the range -128 to 127 inclusive,
then let a and b be the results of any two boxing
conversions of p. It is always the case that a
== b.
Ideally, boxing a primitive value would always yield an identical reference. In practice, this may not be feasible using existing implementation techniques. The rule above is a pragmatic compromise, requiring that certain common values always be boxed into indistinguishable objects. The implementation may cache these, lazily or eagerly. For other values, the rule disallows any assumptions about the identity of the boxed values on the programmer's part. This allows (but does not require) sharing of some or all of these references.
This ensures that in most common cases, the behavior will be the desired one, without imposing an undue performance penalty, especially on small devices. Less memory-limited implementations might, for example, cache all
charandshortvalues, as well asintandlongvalues in the range of -32K to +32K.
If
aandbare variables storing the results of any two boxing conversions of p, then it is always the case thata.equals(b)anda == b.
A boxing conversion may result in an
OutOfMemoryError if a new instance of one of the wrapper
classes (Boolean, Byte,
Character, Short, Integer,
Long, Float, or Double) needs to
be allocated and insufficient storage is available.
Chapter 6: Names
6.5 Determining the Meaning of a Name
6.5.6 Meaning of Expression Names
6.5.6.1 Simple Expression Names
If an expression name consists of a single Identifier, then:
If the expression name appears as a CaseConstant in a switch label (14.11.1), and the type of the selector expression of the enclosing
switchstatement orswitchexpression is an enum class type (8.9), and the enum class declares an enum constant with name Identifier, then the expression name refers to the corresponding implicit field of the enum class.Otherwise, if there is exactly one declaration denoting either a local variable, formal parameter, exception parameter, or field in scope at the point at which the identifier occurs, then the expression name refers to the in-scope variable.
Otherwise, a compile-time error occurs.
If the declaration denotes an instance variable of a class C (8.3.1.1), then all of the following must be true, or a compile-time error occurs:
The expression name does not occur in a static context (8.1.3).
If the expression name occurs in an early construction context of C (8.8.7), then:
it is the left-hand operand of a simple assignment expression (15.26), the declaration of the named variable lacks an initializer, and the simple assignment expression is not enclosed in a lambda expression or inner class declaration that is contained in the early construction context of C.The instance variable is declared by C, not a superclass of C;
Either the declaration of the named variable has no initializer (8.3.2), or C is a value class (8.1.1.5); and
The expression name does not appear in a constructor of C whose body includes an alternate constructor invocation (8.8.7), or a nested class or interface declaration of C (8), or a lambda expression contained by C (15.27).
The expression name does not occur in an early construction context of a subclass of C.If the expression name appears in a nested class or interface declaration of C, then the immediately enclosing class or interface declaration of the expression name is an inner class of C (8.1.3).
For example, the expression name must not appear in the body of a
staticmethod declared by C, nor in the body of an instance method of astaticclass nested within C.
...
These changes allow the declared instance fields of C to be both read and written in an early construction context (except where the field has an initializer that hasn't run yet). JVM bytecode does not allow a larval object's fields to be read during early construction, so as necessary the compiler tracks field values locally in the generated bytecode.
This includes a source-incompatible change preventing field assignments before alternate constructor invocations, as discussed by JDK-8368719.
Chapter 8: Classes
8.1 Class Declarations
8.1.1 Class Modifiers
A class declaration may include class modifiers.
- ClassModifier:
- (one of)
-
Annotation
publicprotectedprivate -
abstractstaticfinalsealednon-sealedstrictfp -
value
The rules concerning annotation modifiers for a class declaration are specified in 9.7.4 and 9.7.5.
The access modifier
public (6.6) pertains
only to top level classes (7.6) and
member classes (8.5, 9.5), not to local classes (14.3) or anonymous classes (15.9.5).
The access modifiers
protected and private pertain only to member
classes.
The modifier static
pertains only to member classes and local classes.
It is a compile-time error if the
same keyword appears more than once as a modifier for a class
declaration, or if a class declaration has more than one of the access
modifiers public, protected, and
private.
It is a compile-time error if a
class declaration has more than one of the modifiers
sealed, non-sealed, and
final.
If two or more (distinct) class modifiers appear in a class declaration, then it is customary, though not required, that they appear in the order consistent with that shown above in the production for ClassModifier.
8.1.1.2 sealed,
non-sealed, and final Classes
A class can be declared
sealed if all its direct subclasses are known when the
class is declared (8.1.6), and no
other direct subclasses are desired or required.
Explicit and exhaustive control over a class's direct subclasses is useful when the class hierarchy is used to model the kinds of values in a domain, rather than as a mechanism for code inheritance and reuse. The direct subclasses may themselves be declared
sealedin order to further control the class hierarchy.
A class can be declared
final if its definition is complete and no subclasses are
desired or required.
It is a compile-time error if a
class is declared both final and abstract,
because the implementation of such a class could never be completed (8.1.1.1).
Because a final class
never has any subclasses, the methods of a final class are
never overridden (8.4.8.1).
A class is freely
extensible if its direct superclass is not sealed (8.1.4), and none of its direct superinterfaces are
sealed (8.1.5), and
it is neither sealed nor final itself.
A class that has a
sealed direct superclass or a sealed direct
superinterface is freely extensible if and only if it is declared
non-sealed.
It is a compile-time error if a
class has a sealed direct superclass or a
sealed direct superinterface, and is not declared
final, sealed, or non-sealed
either explicitly or implicitly.
Thus, an effect of the
sealedkeyword is to force all direct subclasses to explicitly declare whether they arefinal,sealed, ornon-sealed. This avoids accidentally exposing a sealed class hierarchy to unwanted subclassing.
An enum class is either implicitly
finalor implicitlysealed, so it can implement asealedinterface. Similarly,a record class isrecord classes and non-abstractvalue classes are implicitlyfinal, soitthey can also implement a sealed interface.
It is a compile-time error if a
class is declared non-sealed but has neither a
sealed direct superclass nor a sealed direct
superinterface.
Thus, a subclass of a
non-sealedclass cannot itself be declarednon-sealed.
8.1.1.5 value
Classes
The value modifier
specifies that a class does not depend on object identity to
support unique instance creation, instance field mutation, or
synchronization (4.3.1). All instances of a
non-abstract value class are value objects.
A class without the
value modifier is an identity class, and may
depend on features associated with object identity. All instances of an
identity class are identity objects. A value class may not extend an
identity class, with the exception of the identity class
Object (8.1.4).
If a value class is not
abstract, it is implicitly final (8.1.1.2). It is permitted for the class
declaration to redundantly specify the final modifier.
It is a compile-time error if a
value class is not abstract but is declared with the
modifier sealed or non-sealed.
Special restrictions apply to the field declarations (8.3.1.2), method declarations (8.4.3.6), and constructors (8.8.7) of a value class.
Previous iterations of this specification required an
abstract value class to be stateless and have an empty
constructor. This is no longer the case: an abstract value
class may declare instance fields, may be an inner class, and may have
instance initialization logic.
8.1.4 Superclasses and Subclasses
The optional extends
clause in a normal class declaration specifies the direct superclass
type of the class being declared.
- ClassExtends:
-
extendsClassType
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 type.
The ClassType must name an accessible class (6.6), or a compile-time error occurs.
It is a compile-time error if the
ClassType names a class that is sealed (8.1.1.2) and the class being declared is not a
permitted direct subclass of the named class (8.1.6).
It is a compile-time error if the
ClassType names a class that is final, because
final classes are not allowed to have subclasses (8.1.1.2).
It is a compile-time error if the
ClassType names the class Enum, which can only be
extended by an enum class (8.9), or names the
class Record, which can only be extended by a record class
(8.10).
In a value
class, it is a compile-time error if the ClassType names an
identity class (8.1.1.5) other than the class
Object.
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.
The direct superclass type of a
class whose declaration lacks an extends clause is as
follows:
The class
Objecthas no direct superclass type.For a class other than
Objectwith a normal class declaration, the direct superclass type isObject.For an enum class E, the direct superclass type is
Enum<E>.For a record class R, the direct superclass type is
Record.For an anonymous class, the direct superclass type is defined in 15.9.5.
The direct superclass of a class is the class named by its direct superclass type. The direct superclass is important because its implementation is used to derive the implementation of the class being declared.
...
8.3 Field Declarations
8.3.1 Field Modifiers
8.3.1.2 final Fields
A field can be declared
final (4.12.4).
Both class and instance variables (static and
non-static fields) may be declared final.
In a value
class, every non-static field is implicitly
final. It is permitted for the field declaration to
redundantly specify the final modifier.
A blank final class
variable must be definitely assigned by a static initializer of the
class in which it is declared, or a compile-time error occurs (8.7, 16.8).
A blank final
instance variable must be definitely assigned and moreover not
definitely unassigned at the end of every constructor of the class in
which it is declared, or a compile-time error occurs (8.8, 16.9).
Furthermore, when
declared by a value class or a record class, a
blank final instance variable must be definitely assigned
after the argument list of every explicit superclass constructor
invocation (8.8.7.1) in the class, or a
compile-time error occurs.
8.3.2 Field Initialization
If a declarator in a field declaration has a variable initializer, then the declarator has the semantics of an assignment (15.26) to the declared variable.
If the declarator is for a class
variable (that is, a static field) (8.3.1.1), then the following
rules apply to its initializer: the initializer occurs in
a static context (8.1.3);
references to the class variable being declared or forward references to
other class variables are restricted, according to the rules in 8.3.3. At run time,
the initializer is evaluated and the assignment performed exactly once,
when the class is initialized (12.4.2).
The initializer may not refer to the current object using the keyword
thisor the keywordsuper, as specified in 15.8.3 and 15.11.2, nor refer by simple name to any instance variable or instance method, as specified in 6.5.6.1 and 15.12.3.At run time, the initializer is evaluated and the assignment performed exactly once, when the class is initialized (12.4.2).
Note that
staticfields that are constant variables (4.12.4) are initialized before otherstaticfields (12.4.2, step 6). This also applies in interfaces (9.3.1). When such fields are referenced by simple name, they will never be observed to have their default initial values (4.12.5).
If the declarator is for an instance
variable (that is, a field that is not static), then
the following rules apply to its initializer: the
initializer may refer to any class variable of the class, even one whose
declaration occurs to the right of the initializer; references to the
instance variable being declared or forward references to other instance
variables are restricted, according to the rules in 8.3.3. At run time, the initializer
is evaluated and the assignment performed each time an instance of the
class is created (12.5).
The initializer may refer to the current object using the keyword
thisor the keywordsuper, and may refer by simple name to any class variable declared in or inherited by the class, even one whose declaration occurs to the right of the initializer (3.5).At run time, the initializer is evaluated and the assignment performed each time an instance of the class is created (12.5).
If the declarator is for an
instance variable of a value class (8.1.1.5),
then the initializer is an early instance variable initializer
and is evaluated at the start of each constructor that contains a
superclass constructor invocation (either explicit or implicit). The
initializer occurs in an early construction context (8.8.7), which restricts references to the current
object using this and super (15.8.3, 15.11.2), as well as unqualified
references to instance methods (6.5.7.1) and certain unqualified
references to instance variables (6.5.6.1).
If the declarator is for an
instance variable of an identity class, then it is a late instance
variable initializer and is evaluated immediately after each
superclass constructor invocation in the class (either explicit or
implicit). The initializer does not occur in an early
construction context; it may freely refer to the current object using
this and super, and may freely access the
object's instance methods and instance variables.
References from variable
initializers to fields that may not yet be initialized are restricted,
as specified in 8.3.3 and 16.
Exception checking for a variable initializer in a field declaration is specified in 11.2.3.
Variable initializers are also used in local variable declaration statements (14.4), where the initializer is evaluated and the assignment performed each time the local variable declaration statement is executed.
Example 8.3.2-1. Field Initialization
class Point {
int x = 1, y = 5;
}
class Test {
public static void main(String[] args) {
Point p = new Point();
System.out.println(p.x + ", " + p.y);
}
}
This program produces the output:
1, 5
because the assignments to x and y occur
whenever a new Point is created.
Example 8.3.2-2. Forward Reference to a Class Variable
class Test {
float f = j;
static int j = 1;
}
This program compiles without error; it initializes j to
1 when class Test is initialized, and
initializes f to the current value of j every
time an instance of class Test is created.
8.4 Method Declarations
8.4.3 Method Modifiers
8.4.3.6 synchronized Methods
A synchronized method
acquires a monitor (17.1) before it
executes.
For a class (static)
method, the monitor associated with the Class object for
the method's class is used.
For an instance method, the
monitor associated with this (the object for which the
method was invoked) is used.
It is a compile-time
error for a value class to declare a
synchronized instance method.
...
8.8 Constructor Declarations
8.8.7 Constructor Body
A constructor body is a block of code that is executed as part of the process of creating a new instance of a class (12.5). A constructor body may contain an explicit invocation of another constructor of the same class or of the direct superclass (8.8.7.1).
- ConstructorBody:
-
{[BlockStatements] ConstructorInvocation [BlockStatements]} -
{[BlockStatements]}
If a constructor body contains an
explicit constructor invocation, the BlockStatements preceding
the constructor invocation are called the prologue of the
constructor body. The prologue of a constructor body may be empty. The
BlockStatements in a constructor with no explicit
constructor invocation and the BlockStatements following
a constructor invocation in a constructor body are called the
epilogue. The epilogue of a constructor body may also be
empty.
A construct (statement, local
variable declaration statement, local class declaration, local interface
declaration, or expression) occurs in the early construction context
of a class C if it is contained in either the prologue of
a constructor body of C, or it is nested in the
constructor invocation (8.8.7.1) of a
constructor body of C, or an early instance field
initializer (8.3.2) of C.
References to the current object using this and
super are restricted in an early construction context (15.8.3, 15.11.2), as are unqualified
references to instance methods (6.5.7.1) and certain unqualified
references to instance variabes (6.5.6.1).
If the body of a
constructor in a value class (8.1.1.5) or a
record class (8.10) does not contain an explicit
constructor invocation, then the BlockStatements constitute the
prologue and the epilogue is empty. The constructor body implicitly ends
with a superclass constructor invocation "super();", an
invocation of the constructor of the direct superclass that takes no
arguments.
If a constructor body
the body of a constructor in an any other class does
not contain an explicit constructor invocation, then the
prologue is empty and the BlockStatements constitute the
epilogue. and If the constructor
being declared is not part of the primordial class Object,
then the constructor body (i) has an empty prologue, (ii)
implicitly begins with a superclass constructor invocation
"super();", an implicit invocation of the
constructor of the direct superclass that takes no arguments, and
(iii) the statements, if any, given in the constructor body are taken to
form the epilogue of the constructor body.
Except for the possibility of
explicit or implicit constructor invocations, and the prohibition on
return statements (14.17), the body of a constructor
is like the body of a method (8.4.7).
Note that a constructor body contains at most one constructor invocation. The grammar makes it impossible, for example, to place constructor invocations in different branches of an
ifstatement.
Example 8.8.7-1. Constructor Bodies
class Point {
int x, y;
Point(int x, int y) { this.x = x; this.y = y; }
}
class ColoredPoint extends Point {
static final int WHITE = 0, BLACK = 1;
int color;
ColoredPoint(int x, int y) {
this(x, y, WHITE);
}
ColoredPoint(int x, int y, int color) {
super(x, y);
this.color = color;
}
}
Here, the first constructor of ColoredPoint invokes the
second, providing an additional argument; the second constructor of
ColoredPoint invokes the constructor of its superclass
Point, passing along the coordinates.
8.8.7.1 Constructor Invocations
- ConstructorInvocation:
-
[TypeArguments]
this([ArgumentList]); -
[TypeArguments]
super([ArgumentList]); -
ExpressionName
.[TypeArguments]super([ArgumentList]); -
Primary
.[TypeArguments]super([ArgumentList]);
The following productions from 4.5.1 and 15.12 are shown here for convenience:
- TypeArguments:
<TypeArgumentList>- ArgumentList:
- Expression {
,Expression}
Constructor invocations are divided into two kinds:
Alternate constructor invocations begin with the keyword
this(possibly prefaced with explicit type arguments). They are used to invoke an alternate constructor of the same class.Superclass constructor invocations begin with either the keyword
super(possibly prefaced with explicit type arguments) or a Primary expression or an ExpressionName. They are used to invoke a constructor of the direct superclass. They are further divided:Unqualified superclass constructor invocations begin with the keyword
super(possibly prefaced with explicit type arguments).Qualified superclass constructor invocations begin with a Primary expression or an ExpressionName. They allow a subclass constructor to explicitly specify the newly created object's immediately enclosing instance with respect to the direct superclass (8.1.3). This may be necessary when the superclass is an inner class.
It is a compile-time error for a constructor to directly or indirectly invoke itself through a series of one or more alternate constructor invocations.
A constructor invocation
introduces an early construction context (8.8.7), which limits the use of constructs that
refer to the current object. Notably, references to the current object
using this and super are restricted in an
early construction context (15.8.3, 15.11.2), as are references to
instance variables (6.5.6.1) and instance
methods (6.5.7.1).
If TypeArguments is
present to the left of this or super, then it
is a compile-time error if any of the type arguments are wildcards (4.5.1).
Let C be the class being instantiated, and let S be the direct superclass of C.
If a superclass constructor invocation is unqualified, then:
If S is an inner member class, but S is not a member of a class enclosing C, then a compile-time error occurs.
Otherwise, let O be the innermost enclosing class of C of which S is a member. C must be an inner class of O (8.1.3), or a compile-time error occurs. If the superclass constructor invocation occurs in an early construction context of the class O, then a compile-time error occurs.
If S is an inner local class, and S does not occur in a static context, let O be the immediately enclosing class or interface declaration of S. C must be an inner class of O, or a compile-time error occurs.
If S is a inner local class whose declaration occurs in a static context, then let N be the nearest
staticmethod declaration,staticfield declaration, or static initializer that encloses the declaration of S. If N is not the neareststaticmethod declaration,staticfield declaration, or static initializer that encloses the superclass constructor invocation, then a compile-time error occurs.
If a superclass constructor invocation is qualified, then:
If S is not an inner class, or if the declaration of S occurs in a static context, then a compile-time error occurs.
Otherwise, let p be the Primary expression or the ExpressionName immediately preceding "
.super", and let O be the immediately enclosing class of S. It is a compile-time error if the type of p is not O or a subclass of O, or if the type of p is not accessible (6.6).
The exception types that an explicit constructor invocation can throw are specified in 11.2.2.
...
8.9 Enum Classes
An enum declaration specifies a new enum class, a restricted kind of class that defines a small set of named class instances.
- EnumDeclaration:
-
{ClassModifier}
enumTypeIdentifier [ClassImplements] EnumBody
An enum declaration may specify a top level enum class (7.6), a member enum class (8.5, 9.5), or a local enum class (14.3).
The TypeIdentifier in an enum declaration specifies the name of the enum class.
It is a compile-time error if an enum
declaration has the modifier abstract, final,
sealed, or non-sealed, or
value.
An enum class is either implicitly
final or implicitly sealed, as follows:
An enum class is implicitly
finalif its declaration contains no enum constants that have a class body (8.9.1).An enum class E is implicitly
sealedif its declaration contains at least one enum constant that has a class body. The permitted direct subclasses (8.1.6) of E are the anonymous classes implicitly declared by the enum constants that have a class body.
A nested enum class is implicitly
static. That is, every member enum class and local enum
class is static. It is permitted for the declaration of a
member enum class to redundantly specify the static
modifier, but it is not permitted for the declaration of a local enum
class (14.3).
It is a compile-time error if the same
keyword appears more than once as a modifier for an enum declaration, or
if an enum declaration has more than one of the access modifiers
public, protected, and private
(6.6).
The direct superclass type of an enum
class E is Enum<E> (8.1.4).
An enum declaration does not have an
extendsclause, so it is not possible to explicitly declare a direct superclass type, evenEnum<E>.
An enum class has no instances other than those defined by its enum constants. It is a compile-time error to attempt to explicitly instantiate an enum class (15.9.1).
In addition to the compile-time error, three further mechanisms ensure that no instances of an enum class exist beyond those defined by its enum constants:
The
finalclonemethod inEnumensures that enum constants can never be cloned.Reflective instantiation of enum classes is prohibited.
Special treatment by the serialization mechanism ensures that duplicate instances are never created as a result of deserialization.
8.10 Record Classes
A record declaration specifies a new record class, a restricted kind of class that defines a simple aggregate of values.
- RecordDeclaration:
-
{ClassModifier}
recordTypeIdentifier [TypeParameters] RecordHeader
[ClassImplements] RecordBody
A record declaration may specify a top level record class (7.6), a member record class (8.5, 9.5), or a local record class (14.3).
The TypeIdentifier in a record declaration specifies the name of the record class.
It is a compile-time error if a
record declaration has the modifier abstract,
sealed, or non-sealed.
A record class is implicitly
final. It is permitted for the declaration of a record
class to redundantly specify the final modifier.
A nested record class is implicitly
static. That is, every member record class and local record
class is static. It is permitted for the declaration of a
member record class to redundantly specify the static
modifier, but it is not permitted for the declaration of a local record
class (14.3).
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).
A record class may be a
value class or an identity class (8.1.1.5).
A record class is often a good candidate to be a
valueclass, because its instance fields are alwaysfinaland its implicitly declaredequalsmethod makes no use of identity (8.10.3).
The direct superclass type of a
record class is Record (8.1.4).
A record declaration does not have an
extendsclause, so it is not possible to explicitly declare a direct superclass type, evenRecord.
The serialization mechanism treats instances of a record class differently than ordinary serializable or externalizable objects. In particular, a record object is deserialized using the canonical constructor (8.10.4).
8.10.4 Record Constructor Declarations
8.10.4.1 Normal Canonical Constructors
A (non-compact) constructor in the declaration of record class R is the canonical constructor of R if its signature is override-equivalent (8.4.2) to the derived constructor signature of R.
The derived constructor signature of a record class R is a signature that consists of the name R, no type parameters, and the formal parameter types derived from the record header of R by taking the declared type of each record component in order.
As a canonical constructor has a signature that is override-equivalent to the derived constructor signature of the record class, there can be only one canonical constructor declared explicitly in the record class.
The declaration of a (non-compact) canonical constructor must satisfy all of the following conditions, or a compile-time error occurs:
Each formal parameter in the formal parameter list must have the same name and declared type as the corresponding record component.
A formal parameter must be a variable arity parameter if and only if the corresponding record component is a variable arity record component.
The constructor must not be generic (8.8.4).
The constructor must not have a
throwsclause.The constructor body must not contain an explicit constructor invocation (8.8.7.1).All the other rules for constructor declarations in a normal class declaration must be satisfied (8.8).
A consequence of these rules is that the annotations on a record component can differ from the annotations on the corresponding formal parameter of an explicitly declared canonical constructor. For example, the following record declaration is valid:
import java.lang.annotation.Target; import java.lang.annotation.ElementType; @interface Foo {} @interface Bar {} record Person(@Foo String name) { Person(@Bar String name) { this.name = name; } }
This change allows an explicit super() in the canonical
constructor of a record class. Normally, all of a record class's
canonical constructor code appears in an early construction context (8.8.7). A developer may wish to use an explicit
super() invocation in rare cases where some of the
construction logic needs to refer to this. Doing so is fine
as long as, per 8.3.1.2, all of the record
class's fields are set before super() is invoked.
8.10.4.2 Compact Canonical Constructors
A compact constructor declaration is a succinct form of constructor declaration, only available in a record declaration. It declares the canonical constructor of a record class without requiring the record components of the class to be manually repeated as formal parameters of the constructor.
- CompactConstructorDeclaration:
- {ConstructorModifier} SimpleTypeName ConstructorBody
The following productions from 8.8, 8.8.3, and 8.8.7 are shown here for convenience:
- ConstructorModifier:
- (one of)
- Annotation
publicprotectedprivate- SimpleTypeName:
- TypeIdentifier
- ConstructorBody:
{[BlockStatements] ConstructorInvocation [BlockStatements]}{[BlockStatements]}
It is a compile-time error for a record declaration to have more than one compact constructor declaration.
The formal parameters of a compact constructor of a record class are implicitly declared. They are given by the derived formal parameter list of the record class (8.10.4).
The compact constructor of a record class is a variable arity constructor (8.8.1) if the record class has a variable arity record component.
The signature of a compact constructor declaration is equal to the derived constructor signature of the record class (8.10.4.1).
The body of a compact constructor declaration must satisfy all of the following conditions, or a compile-time error occurs:
The body must not contain a
returnstatement (14.17).The body must not contain an explicit constructor invocation (8.8.7.1).
The body must not contain an assignment to a component field of the record class.
All the other rules for a constructor in a normal class declaration must be satisfied (8.8), except for the requirement that the component fields of the record class must be definitely assigned and moreover not definitely unassigned at the end of the compact constructor (8.3.1.2).
The body of a compact constructor occurs in an early
construction context (8.8.7), which restricts
references to the current object using this and
super (15.8.3, 15.11.2), as well as unqualified
references to instance methods (6.5.7.1) and certain unqualified
references to instance variables (6.5.6.1).
If a record declaration has a record component named c, then the simple name c in the body of a compact constructor denotes the implicit formal parameter named c, and not the component field named c.
After the last statement, if any, in the body of the compact constructor has completed normally (14.1), all component fields of the record class are implicitly initialized to the values of the corresponding formal parameters. The component fields are initialized in the order that the corresponding record components are declared in the record header.
The intent of a compact constructor declaration is that only code to validate or normalize parameters needs to be given in the constructor body; the remaining initialization code is supplied by the compiler. For example, the following record class has a compact constructor that simplifies a rational number:
record Rational(int num, int denom) { private static int gcd(int a, int b) { if (b == 0) return Math.abs(a); else return gcd(b, a % b); } Rational { int gcd = gcd(num, denom); num /= gcd; denom /= gcd; } }
The compact constructor
Rational {...}behaves the same as this normal constructor:
Rational(int num, int denom) { int gcd = gcd(num, denom); num /= gcd; denom /= gcd; this.num = num; this.denom = denom;super();}
Chapter 12: Execution
12.5 Creation of New Class Instances
A new class instance is explicitly created when evaluation of a class instance creation expression (15.9) causes a class to be instantiated.
A new class instance may be implicitly created in the following situations:
Loading of a class or interface that contains a string literal (3.10.5) or a text block (3.10.6) may create a new
Stringobject to denote the string represented by the string literal or text block. (This object creation will not occur if an instance ofStringdenoting the same sequence of Unicode code points as the string represented by the string literal or text block has previously been interned.)Execution of an operation that causes boxing conversion (5.1.7). Boxing conversion may create a new object of a wrapper class (
Boolean,Byte,Short,Character,Integer,Long,Float,Double) associated with one of the primitive types.Execution of a string concatenation operator
+(15.18.1) that is not part of a constant expression (15.29) always creates a newStringobject to represent the result. String concatenation operators may also create temporary wrapper objects for a value of a primitive type.Evaluation of a method reference expression (15.13.3) or a lambda expression (15.27.4) may require that a new instance be created of a class that implements a functional interface type (9.8).
Each of these situations identifies a particular constructor (8.8) to be called with specified arguments (possibly none) as part of the class instance creation process.
Whenever a new class instance is created, memory space is allocated for it with room for all the instance variables declared in the class and all the instance variables declared in each superclass of the class, including all the instance variables that may be hidden (8.3).
If there is not sufficient space
available to allocate memory for the object, then creation of the class
instance completes abruptly with an OutOfMemoryError.
Otherwise, all the instance variables in the new object, including those
declared in superclasses, are initialized to their default values (4.12.5).
Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:
Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.
If this constructor does not contain an explicit constructor invocation (8.8.7.1) then continue from step 5.If this constructor is declared in a value class (8.1.1.5) and does not contain an alternate constructor invocation (8.8.7.1), execute the early instance variable initializers for this class (8.3.2), assigning the values of the initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code of the class. If execution of any of these initializers results in an exception, then no further initializers are processed and this procedure completes abruptly with that same exception, otherwise continue with the next step.Execute the BlockStatements, if any, of the prologue of the constructor body. If execution of any statement completes abruptly, then execution of the constructor completes abruptly for the same reason, otherwise continue with the next step.
If this constructor contains an explicit constructor invocation,
The explicit constructorthe invocation is either an invocation of another constructor in the same class (usingthis) or an invocation of a superclass constructor (usingsuper). Evaluate the arguments of the constructor invocation and process the constructor invocation recursively using these same seven steps. If the constructor invocation completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, continue from step 7 if the invocation is of another constructor in the same class, and continue from step 6 if the invocation is of a superclass constructor.If this constructor contains no explicit constructor invocation and is for a class other than
Object, then this constructor contains an implicit invocation of a superclass constructor with no arguments. In this case, process the implicit constructor invocation recursively using these same seven steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason, otherwise continue with the next step.Execute the instance initializers and late instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class. If execution of any of these initializers results in an exception, then no further initializers are processed and this procedure completes abruptly with that same exception, otherwise continue with the next step.
In a value class, the instance variable initializers are all early initializers and were already executed in step 2.
Execute the BlockStatements, if any, of the epilogue of this constructor. If execution of any statement completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, this procedure completes normally.
Unlike C++, the Java programming language does not specify altered rules for method dispatch during the creation of a new class instance. If methods are invoked that are overridden in subclasses in the object being initialized, then these overriding methods are used, even before the new object is completely initialized. Classes can avoid unwanted exposure of uninitialized state by assigning to their fields in the prologue of the constructor body.
Example 12.5-1. Evaluation of Instance Creation
class Point {
int x, y;
Point() { x = 1; y = 1; }
}
class ColoredPoint extends Point {
int color = 0xFF00FF;
}
class Test {
public static void main(String[] args) {
ColoredPoint cp = new ColoredPoint();
System.out.println(cp.color);
}
}
Here, a new instance of ColoredPoint is created. First,
space is allocated for the new ColoredPoint, to hold the
fields x, y, and color. All these
fields are then initialized to their default values (in this case,
0 for each field). Next, the ColoredPoint
constructor with no arguments is first invoked. Since
ColoredPoint declares no constructors, a default
constructor of the following form is implicitly declared:
ColoredPoint() { super(); }
This constructor then invokes the Point constructor with
no arguments. The Point constructor does not begin with an
invocation of a constructor, so the Java compiler provides an implicit
invocation of its superclass constructor of no arguments, as though it
had been written:
Point() { super(); x = 1; y = 1; }
Therefore, the constructor for Object which takes no
arguments is invoked.
The class Object has no superclass, so the recursion
terminates here. Next, any instance initializers and instance variable
initializers of Object are invoked. Next, the body of the
constructor of Object that takes no arguments is executed.
No such constructor is declared in Object, so the Java
compiler supplies a default one, which in this special case is:
Object() { }
This constructor executes without effect and returns.
Next, all initializers for the instance variables of class
Point are executed. As it happens, the declarations of
x and y do not provide any initialization
expressions, so no action is required for this step of the example. Then
the body of the Point constructor is executed, setting
x to 1 and y to
1.
Next, the initializers for the instance variables of class
ColoredPoint are executed. This step assigns the value
0xFF00FF to color. Finally, the epilogue of
the ColoredPoint constructor is executed (the part after
the invocation of super); there happen to be no statements
in the epilogue, so no further action is required and initialization is
complete.
Example 12.5-2. Dynamic Dispatch During Instance Creation
class Super {
Super() { printThree(); }
void printThree() { System.out.println("three"); }
}
class Test extends Super {
int three = (int)Math.PI; // That is, 3
void printThree() { System.out.println(three); }
public static void main(String[] args) {
Test t = new Test();
t.printThree();
}
}
This program produces the output:
0
3
This shows that the invocation of printThree in the
constructor for class Super does not invoke the definition
of printThree in class Super, but rather
invokes the overriding definition of printThree in class
Test. This method therefore runs before the field
initializers of Test have been executed, which is why the
first value output is 0, the default value to which the
field three of Test is initialized. The later
invocation of printThree in method main
invokes the same definition of printThree, but by that
point the initializer for instance variable three has been
executed, and so the value 3 is printed.
Example 12.5-3. Initialization of Fields in the Prologue
class Super {
Super() { printThree(); }
void printThree() { System.out.println("three"); }
}
class Test extends Super {
int three;
public Test() {
three = (int)Math.PI; // That is, 3
super();
}
void printThree() { System.out.println(three); }
public static void main(String[] args) {
Test t = new Test();
t.printThree();
}
}
This alternative to Example 12.5-2 produces the output:
3
3
Because the field three is initialized in the prologue
of the Test constructor, its assignment occurs in Step 3 of
the object initialization procedure, before execution of the
Super constructor in Step 4. When three is
initialized in this way, it is impossible to observe it with the default
value 0.
Chapter 13: Binary Compatibility
13.4 Evolution of Classes
This section describes the effects of changes to the declaration of a class and its members and constructors on pre-existing binaries.
13.4.1 abstract and
value Classes
If a class that was not declared
abstract is changed to be declared abstract,
then pre-existing binaries that attempt to create new instances of that
class will throw either an InstantiationError at link time,
or (if a reflective method is used) an
InstantiationException at run time; such a change is
therefore not recommended for widely distributed classes.
Changing a an
identity class that is declared abstract to no
longer be declared abstract does not break compatibility
with pre-existing binaries.
Removing the abstract
modifier from a value class declaration has the side-effect of making
the class final, with binary compatibility risks outlined
in 13.4.2.3.
Modifying an abstract
or final identity class to be a value class does not break
compatibility with pre-existing binaries.
Adding the value
modifier to a non-abstract, non-final class
declaration has the side-effect of making the class final,
with binary compatibility risks outlined in 13.4.2.3.
Removing the value
modifier from a non-abstract value class does not break
compatibility with pre-existing binaries.
Removing the value
modifier from an abstract value class causes an
IncompatibleClassChangeError to be thrown whenever a binary
of a pre-existing value subclass of the class is loaded, because value
classes cannot extend identity classes (8.1.4);
such a change is not recommended for widely distributed classes.
Aside from binary compatibility risks, changing an identity class to be a value class, or vice versa, will change instances' behavior with respect to indentity-sensitive operations like
==(15.21.3) andsynchronized(14.19), and may affect the timing of initializer and constructor logic (12.5).
Chapter 14: Blocks, Statements, and Patterns
14.19 The synchronized Statement
A synchronized
statement acquires a mutual-exclusion lock (17.1) on behalf of the executing thread, executes a
block, then releases the lock. While the executing thread owns the lock,
no other thread may acquire the lock.
- SynchronizedStatement:
-
synchronized(Expression)Block
The type of Expression must
be a reference type, and must not be a final value
class type, or a type variable or intersection type bounded by a
final value class type, or a compile-time error
occurs.
A synchronized
statement is executed by first evaluating the Expression.
Then:
If evaluation of the Expression completes abruptly for some reason, then the
synchronizedstatement completes abruptly for the same reason.Otherwise, if the value of the Expression is
null, aNullPointerExceptionis thrown.Otherwise, if the value of the Expression is a reference to a value object, an
IdentityExceptionis thrown.Otherwise, let the non-
nullvalue of the Expression be V. The executing thread locks the monitor associated with V. Then the Block is executed, and then there is a choice:If execution of the Block completes normally, then the monitor is unlocked and the
synchronizedstatement completes normally.If execution of the Block completes abruptly for any reason, then the monitor is unlocked and the
synchronizedstatement completes abruptly for the same reason.
The locks acquired by
synchronized statements are the same as the locks that are
acquired implicitly by synchronized methods (8.4.3.6). A single thread may acquire a lock
more than once.
Acquiring the lock associated with
an identity object does not in itself prevent other
threads from accessing fields of the object or invoking
un-synchronized methods on the object. Other threads can
also use synchronized methods or the
synchronized statement in a conventional manner to achieve
mutual exclusion.
Example 14.19-1. The synchronized Statement
class Test {
public static void main(String[] args) {
Test t = new Test();
synchronized(t) {
synchronized(t) {
System.out.println("made it!");
}
}
}
}
This program produces the output:
made it!
Note that this program would deadlock if a single thread were not permitted to lock a monitor more than once.
Chapter 15: Expressions
15.8 Primary Expressions
15.8.3 this
The keyword this may
be used as an expression in the following contexts:
in the body of an instance method of a class (8.4.3.2)
in the body of a constructor of a class (8.8.7)
in an instance initializer of a class (8.6)
in the initializer of an instance variable of a class (8.3.2)
in the body of an instance method of an interface, that is, a default method or a non-
staticprivateinterface method (9.4)
When used as an expression, the
keyword this denotes a value that is a reference either to
the object for which the instance method was invoked (15.12), or to the object being
constructed. The value denoted by this in a lambda body (15.27.2) is the same as the value
denoted by this in the surrounding context.
The keyword
thisis also used in constructor invocations (8.8.7.1), and to denote the receiver parameter of a method or constructor (8.4).
It is a compile-time error if a
this expression occurs in a static context (8.1.3).
Let C be the innermost
enclosing class or interface declaration of a this
expression.
It is a compile-time error if a
this expression occurs in an early construction context (8.8.7) of C, unless it appears as the
qualifier of a field access expression (15.11) that is the left-hand
operand of a simple assignment expression (15.26), and the simple
assignment field access expression is not
enclosed in a lambda expression or inner class declaration that is
contained in the early construction context of C.
If C is generic, with type
parameters F1,...,Fn, the type
of this is
C<F1,...,Fn>.
Otherwise, the type of this is C.
At run time, the class of the actual object referred to may be C or a subclass of C (8.1.5).
Example 15.8.3-1. The this Expression
class IntVector {
int[] v;
boolean equals(IntVector other) {
if (this == other)
return true;
if (v.length != other.v.length)
return false;
for (int i = 0; i < v.length; i++) {
if (v[i] != other.v[i]) return false;
}
return true;
}
}
Here, the class IntVector implements a method
equals, which compares two vectors. If the other vector is
the same vector object as the one for which the equals
method was invoked, then the check can skip the length and value
comparisons. The equals method implements this check by
comparing the reference to the other object to this.
15.8.4 Qualified this
Any lexically enclosing instance
(8.1.3) can be referred to by
explicitly qualifying the keyword this.
Let n be an integer such
that TypeName denotes the n'th lexically enclosing
class or interface declaration of the class or interface whose
declaration immediately encloses the qualified this
expression.
The value of a qualified
this expression TypeName.this is the
n'th lexically enclosing instance of this.
If TypeName denotes a
generic class, with type parameters
F1,...,Fn, the type of the
qualified this expression is
TypeName<F1,...,Fn>.
Otherwise, the type of the qualified this expression is
TypeName.
It is a compile-time error if a
qualified this expression occurs in a static context (8.1.3).
It is a compile-time error if a
qualified this expression occurs in an early construction
context (8.8.7) of the class named by
TypeName, unless it appears as the qualifier of a field access
expression (15.11) that is
the left-hand operand of a simple assignment expression (15.26), and the simple
assignment field access expression is not
enclosed in a lambda expression or inner class declaration that is
contained in the early construction context of the class named by
TypeName.
It is a compile-time error if the
class or interface whose declaration immediately encloses a qualified
this expression is not an inner class of TypeName
or TypeName itself.
15.9 Class Instance Creation Expressions
15.9.4 Run-Time Evaluation of Class Instance Creation Expressions
At run time, evaluation of a class instance creation expression is as follows.
First, if the class instance
creation expression is a qualified class instance creation expression,
the qualifying primary expression is evaluated. If the qualifying
expression evaluates to null, a
NullPointerException is raised, and the class instance
creation expression completes abruptly. If the qualifying expression
completes abruptly, the class instance creation expression completes
abruptly for the same reason.
Next, space is allocated for the
new class instance. If there is insufficient space to allocate the
object, evaluation of the class instance creation expression completes
abruptly by throwing an OutOfMemoryError.
The new object contains new instances of all the fields declared in the specified class and all its superclasses. As each new field instance is created, it is initialized to its default value (4.12.5).
Next, the actual arguments to the constructor are evaluated, left-to-right. If any of the argument evaluations completes abruptly, any argument expressions to its right are not evaluated, and the class instance creation expression completes abruptly for the same reason.
Next, the selected constructor of the specified class is invoked. This results in invoking at least one constructor for each superclass of the class. This process can be directed by explicit constructor invocations (8.8.7.1) and is specified in detail in 12.5.
The value of a class instance
creation expression is a reference to the newly created object of the
specified class. Every time If the specified class is
an identity class, then every time the expression is evaluated,
a fresh object is created the object that is created
has a unique identity.
Example 15.9.4-1. Evaluation Order and Out-Of-Memory Detection
If evaluation of a class instance creation expression finds there is
insufficient memory to perform the creation operation, then an
OutOfMemoryError is thrown. This check occurs before any
argument expressions are evaluated.
So, for example, the test program:
class List {
int value;
List next;
static List head = new List(0);
List(int n) { value = n; next = head; head = this; }
}
class Test {
public static void main(String[] args) {
int id = 0, oldid = 0;
try {
for (;;) {
++id;
new List(oldid = id);
}
} catch (Error e) {
List.head = null;
System.out.println(e.getClass() + ", " + (oldid==id));
}
}
}
prints:
class java.lang.OutOfMemoryError, false
because the out-of-memory condition is detected before the argument
expression oldid = id is evaluated.
Compare this to the treatment of array creation expressions, for which the out-of-memory condition is detected after evaluation of the dimension expressions (15.10.2).
15.9.5 Anonymous Class Declarations
An anonymous class is implicitly declared by a class instance creation expression or by an enum constant that ends with a class body (8.9.1).
An anonymous class is never
abstract (8.1.1.1).
An anonymous class is never
sealed (8.1.1.2), and thus has
no permitted direct subclasses (8.1.6).
An anonymous class declared by a
class instance creation expression is never final (8.1.1.2).
An anonymous class declared by an
enum constant is always final.
An anonymous class being non-
finalis relevant in casting, in particular the narrowing reference conversion allowed for the cast operator (5.5). On the other hand, it is not relevant to subclassing, because it is impossible to declare a subclass of an anonymous class (an anonymous class cannot be named by anextendsclause) despite the anonymous class being non-final.
An anonymous class is always an identity class (8.1.1.5) and an inner class (8.1.3).
Like a local class or interface (14.3), an anonymous class is not a member of any package, class, or interface (7.1, 8.5).
The direct superclass type or
direct superinterface type of an anonymous class declared by a class
instance creation expression is given by the expression (15.9.1), with type arguments
inferred as necessary while choosing a constructor (15.9.3). If a direct
superinterface type is given, the direct superclass type is
Object.
The direct superclass type of an anonymous class declared by an enum constant is the type of the declaring enum class.
The ClassBody of the class instance creation expression or enum constant declares fields (8.3), methods (8.4), member classes (8.5), member interfaces (9.1.1.3), instance initializers (8.6), and static initializers (8.7) of the anonymous class. The constructor of an anonymous class is always implicit (15.9.5.1).
If a class instance creation
expression with a ClassBody uses a diamond
(<>) for the type arguments of the class to be
instantiated, then for all non-private methods declared in
the ClassBody, it is as if the method declaration is annotated
with @Override (9.6.4.4).
When
<>is used, the inferred type arguments may not be as anticipated by the programmer. Consequently, the supertype of the anonymous class may not be as anticipated, and methods declared in the anonymous class may not override supertype methods as intended. Treating such methods as if annotated with@Override(if they are not explicitly annotated with@Override) helps avoid silently incorrect programs.
15.21 Equality Operators
15.21.3 Reference
Object Equality Operators == and
!=
If the operands of an equality operator are both of either reference type or the null type, then the operation is object equality.
It is a compile-time error if it
is impossible to convert the type of either operand to the type of the
other by a casting conversion (5.5). The run-time values of the two
operands would necessarily be unequal (ignoring the case where both
values are null).
At run time, the result of
== is true if the operand values are both
null, or both refer to the same
identity object or array, or both
refer to statewise-equivalent value objects;
otherwise, the result is false.
Two value objects are
statewise equivalent if they are instances of the same class
and the values of their instance fields are the same. For
primitive-typed instance fields, this means the field values are
identical (in the case of a floating-point type, all bits of the value
are compared, as if by first applying
Float.floatToRawIntBits or
Double.doubleToRawLongBits). For reference-typed instance
fields, this means the field values are ==, possibly
applying this definition recursively.
The result of != is
false if the operand values are both
null, or both refer to the same
identity object or array, or both
refer to statewise-equivalent value objects; otherwise, the
result is true.
While == may be used
to compare references of type String, such an equality test
determines whether or not the two operands refer to the same
String object. The result is false if the
operands are distinct String objects, even if they contain
the same sequence of characters (3.10.5, 3.10.6). The contents of two
strings s and t can be tested for equality by
the method invocation s.equals(t).
A common mistake is to use the
==operator to test for the same identity object or statewise-equivalent value objects, when what is usually wanted is more abstract: testing whether two objects represent the same value or entity. Theequalsmethod serves this purpose, allowing classes to declare an appropriate domain-specific notion of equality.For example, two distinct
Stringobjects,sandt, may contain the same sequence of characters. A comparison of these objects usings == twill evaluate tofalse, while in most cases the program ought to uses.equals(t)to compare the character sequences that the objects represent.
Chapter 16: Definite Assignment
Every local variable declared by a
statement (14.4.2, 14.14.1, 14.14.2, 14.20.3) and every blank
final field (4.12.4, 8.3.1.2) must have a definitely
assigned value when any access of its value occurs.
An access to its value consists of the
simple name of the variable (or, for a field, the simple name of the
field qualified by this) occurring anywhere in an
expression except as the left-hand operand of the simple assignment
operator = (15.26.1).
For every access of a local variable
declared by a statement x, or blank final field
x, x must be definitely assigned before the access, or
a compile-time error occurs.
Similarly, every blank
final variable must be assigned at most once; it must be
definitely unassigned when an assignment to it occurs.
Such an assignment is defined to occur
if and only if either the simple name of the variable (or, for a field,
its simple name qualified by this) occurs on the left hand
side of an assignment operator.
For every assignment to a blank
final variable, the variable must be definitely unassigned
before the assignment, or a compile-time error occurs.
Similarly, for every alternate
constructor invocation (8.8.7.1) occurring in
a constructor of a class C, every blank final
instance variable of C declared in C must be
definitely unassigned after the argument list of the alternate
constructor invocation, or a compile-time error occurs.
This rule is no longer necessary with the changes to 6.5.6.1. (See also JDK-8368719.)
Note that local variables declared by a pattern (14.30) are not subject to the rules of definite assignment. Every local variable declared by a pattern is initialized by the process of pattern matching and so always has a value when accessed.
...
16.9 Definite Assignment, Constructors, and Instance Initializers
Let C be a class declared within the scope of V. Then:
V is definitely assigned before a constructor declaration (8.8.7) or instance variable initializer (8.3.2) of C iff V is definitely assigned before the declaration of C.
Note that there are no rules that would allow us to conclude that V is definitely unassigned before the constructor declaration or instance variable initializer. We can informally conclude that V is not definitely unassigned before any constructor declaration or instance variable initializer of C, but there is no need for such a rule to be stated explicitly.
Let C be a class, and let
V be a blank final non-static member
field of C, declared in C. Then:
V is definitely unassigned (and moreover is not definitely assigned) before the declaration of any constructor in C.
V is definitely unassigned (and moreover is not definitely assigned) before the leftmost early instance variable initializer of C (8.3.2).
V is [un]assigned before an early instance variable initializer of C other than the leftmost iff V is [un]assigned after the preceding early instance variable initializer of C.
V is definitely unassigned (and moreover is not definitely assigned) before the leftmost instance initializer (8.6) or late instance variable initializer of C iff:
V is definitely unassigned after every superclass constructor invocation (8.8.7.1) in the constructors of C; and
V is definitely unassigned after every prologue of a constructor of C with an implicit superclass constructor invocation.
V is definitely assigned (and moreover is not definitely unassigned) before the leftmost instance initializer (8.6) or late instance variable initializer of C iff:
C declares at least one constructor
,;every constructor of C has an explicit constructor invocation, andV is definitely assigned after every superclass constructor invocation inthese constructors.the constructors of C; andV is definitely assigned after every prologue of a constructor of C with an implicit superclass constructor invocation.
V is [un]assigned before an instance initializer or late instance variable initializer of C other than the leftmost iff V is [un]assigned after the preceding instance initializer or late instance variable initializer of C.
Let C be a class, and let
V be a blank final non-static member
field of C, declared in a superclass of C. Then:
V is definitely unassigned (and moreover is not definitely assigned) before
the declaration of any constructorevery constructor declaration and early instance variable initializer ofinC.In practice, there is no way to access the superclass field from an early construction context, so its definite assignment status does not matter.
V is definitely assigned (and moreover is not definitely unassigned) before every instance initializer and late instance variable initializer of C.
Let C be a class, and let
V be a blank final static member
field of C. Then:
- V is definitely assigned (and moreover is not definitely unassigned) before every constructor declaration, instance initializer, and instance variable initializer of C.
Let C be a class, and let V be a local variable declared by a statement S contained by a constructor or instance variable initializer of C. Then:
- V is definitely unassigned (and moreover is not definitely assigned) before the constructor declaration or instance variable initializer.
The following rules hold within the
constructors (8.8.7) of class
C:
A blank
finalnon-staticmember field V of C, declared in C, is [un]assigned before the prologue of a constructor body (8.8.7) that contains an explicit or implicit superclass constructor invocation (8.8.7.1) iff either V is [un]assigned after the rightmost early instance variable initializer of C, or C declares no early instance variable initializer, and V is [un]assigned before the constructor declaration.For any other variable or constructor, V is [un]assigned before the prologue of the constructor body
(8.8.7)iff V is [un]assigned before the constructor declaration.V is [un]assigned after an empty prologue iff V is [un]assigned before the prologue.
V is [un]assigned after a non-empty prologue iff V is [un]assigned after the last statement in the prologue.
V is [un]assigned before a constructor invocation (8.8.7.1) iff V is [un]assigned after the prologue.
V is [un]assigned before the argument list of a qualified super constructor invocation iff V is [un]assigned after the qualifier expression.
V is [un]assigned before the argument list of any other constructor invocation iff V is [un]assigned before the invocation.
V is [un]assigned after the argument list of a constructor invocation iff either V is [un]assigned after the rightmost argument expression in the argument list, or the argument list is empty and V is [un]assigned before the argument list.
A blank
finalnon-staticmember field of C, declared in a superclass of C, is definitely assigned (and moreover is not definitely unassigned) after a superclass constructor invocation.Any other variable V is [un]assigned after a superclass constructor invocation iff V is [un]assigned after the argument list of the invocation.
A blank
finalnon-staticmember field of C, declared in C or a superclass of C, is definitely assigned (and moreover is not definitely unassigned) after an alternate constructor invocation.Any other variable V is [un]assigned after an alternate constructor invocation iff V is [un]assigned after the argument list of the invocation.
For the epilogue of a constructor body with no explicit constructor invocation:
A blank
finalnon-staticmember field V of C, declared in C, is [un]assigned before the epilogue iff either V is [un]assigned after the rightmost instance initialization or late instance variable initializer of C, or C declares no instance initializer or late instance variable initializer, and V is [un]assigned after the prologue of the constructor body.A blank
finalnon-staticmember field of C, declared in a superclass of C, is definitely assigned (and moreover is not definitely unassigned) before the epilogue.Any other variable V is [un]assigned before the epilogue iff V is [un]assigned after the prologue of the constructor body.
For the epilogue of a constructor body with a superclass constructor invocation:
A blank
finalnon-staticmember field V of C, declared in C, is [un]assigned before the epilogue iff either V is [un]assigned after the rightmost instance initialization or late instance variable initializer of C, or C declares no instance initializer or late instance variable initializer, and V is [un]assigned after the superclass constructor invocation.Any other variable V is [un]assigned before the epilogue iff V is [un]assigned after the superclass constructor invocation.
For the epilogue of a constructor body with an alternate constructor invocation, V is [un]assigned before the epilogue iff V is [un]assigned after the alternate constructor invocation.
V is [un]assigned after an empty epilogue iff V is [un]assigned before the epilogue.
V is [un]assigned after a non-empty epilogue iff V is [un]assigned after the last statement in the epilogue.
V is [un]assigned before the first statement of the prologue or epilogue iff V is [un]assigned before the prologue or epilogue, respectively.
V is [un]assigned before any other statement S in the prologue or epilogue iff V is [un]assigned after the statement immediately preceding S in the prologue or epilogue.
V is [un]assigned before the qualifier expression of a super constructor invocation iff V is [un]assigned before the super constructor invocation.
V is [un]assigned before the leftmost argument expression of an explicit constructor invocation iff V is [un]assigned before the argument list.
V is [un]assigned before any other argument expression x of an explicit constructor invocation iff V is [un]assigned after the argument expression to the left of x.
Chapter 17: Threads and Locks
17.1 Synchronization
The Java programming language provides multiple mechanisms for communicating between threads. The most basic of these methods is synchronization, which is implemented using monitors. Each identity object in Java is associated with a monitor, which a thread can lock or unlock. Only one thread at a time may hold a lock on a monitor. Any other threads attempting to lock that monitor are blocked until they can obtain a lock on that monitor. A thread t may lock a particular monitor multiple times; each unlock reverses the effect of one lock operation.
The synchronized
statement (14.19) computes a reference to an
object; it then attempts to perform a lock action on that object's
monitor and does not proceed further until the lock action has
successfully completed. After the lock action has been performed, the
body of the synchronized statement is executed. If
execution of the body is ever completed, either normally or abruptly, an
unlock action is automatically performed on that same monitor.
A synchronized method
(8.4.3.6) automatically performs a lock
action when it is invoked; its body is not executed until the lock
action has successfully completed. If the method is an instance method,
it locks the monitor associated with the instance for which it was
invoked (that is, the object that will be known as this
during execution of the body of the method). If the method is
static, it locks the monitor associated with the
Class object that represents the class in which the method
is defined. If execution of the method's body is ever completed, either
normally or abruptly, an unlock action is automatically performed on
that same monitor.
The Java programming language neither prevents nor requires detection of deadlock conditions. Programs where threads hold (directly or indirectly) locks on multiple objects should use conventional techniques for deadlock avoidance, creating higher-level locking primitives that do not deadlock, if necessary.
Other mechanisms, such as reads and
writes of volatile variables and the use of classes in the
java.util.concurrent package, provide alternative ways of
synchronization.
17.2 Wait Sets and Notification
Every identity object, in addition to having an associated monitor, has an associated wait set. A wait set is a set of threads.
When an identity
object is first created, its wait set is empty. Elementary actions that
add threads to and remove threads from wait sets are atomic. Wait sets
are manipulated solely through the methods Object.wait,
Object.notify, and Object.notifyAll.
Wait set manipulations can also be
affected by the interruption status of a thread, and by the
Thread class's methods dealing with interruption.
Additionally, the Thread class's methods for sleeping and
joining other threads have properties derived from those of wait and
notification actions.
17.5 final Field Semantics
17.5.1 Semantics of final Fields
Let o be an object, and
c be a constructor for o in which a final
field f is written. A freeze action on
final field f of o takes place when
c exits, either normally or abruptly. as
follows:
In a value class, the freeze action occurs immediately before the constructor invocation in c transfers control to another constructor.
In an identity class, the freeze action occurs when c exits, either normally or abruptly.
The JLS is concerned with the semantics of Java programs, so we do not address here other kinds of strict fields (both final and non-final) that can only be expressed in bytecode. But the intent is that the timing of a freeze action for one of these fields would be the same as in a value class.
Note that if one constructor
invokes another constructor, and the invoked constructor sets a
final field, the freeze for the final field
takes place at the end of the invoked constructor.
For each execution, the behavior of reads is influenced by two additional partial orders, the dereference chain dereferences() and the memory chain mc(), which are considered to be part of the execution (and thus, fixed for any particular execution). These partial orders must satisfy the following constraints (which need not have a unique solution):
Dereference Chain: If an action a is a read or write of a field or element of an object o by a thread t that did not initialize o, then there must exist some read r by thread t that sees the address of o such that r dereferences(r, a).
Memory Chain: There are several constraints on the memory chain ordering:
If r is a read that sees a write w, then it must be the case that mc(w, r).
If r and a are actions such that dereferences(r, a), then it must be the case that mc(r, a).
If w is a write of the address of an object o by a thread t that did not initialize o, then there must exist some read r by thread t that sees the address of o such that mc(r, w).
Given a write w, a freeze
f, an action a (that is not a read of a
final field), a read r1 of the
final field frozen by f, and a read
r2 such that hb(w, f), hb(f, a),
mc(a, r1), and dereferences(r1,
r2), then when determining which values can be seen by
r2, we consider hb(w, r2). (This
happens-before ordering does not transitively close with other
happens-before orderings.)
Note that the dereferences order is reflexive, and r1 can be the same as r2.
For reads of final
fields, the only writes that are deemed to come before the read of the
final field are the ones derived through the
final field semantics.
17.5.3 Subsequent Modification of final
Fields
In some cases, such as
deserialization, the system will need to change the final
fields of an object after construction. The
final instance fields of a
non-record identity class can be changed via
reflection and other implementation-dependent means. The only pattern in
which this has reasonable semantics is one in which an object is
constructed and then the final fields of the object are
updated. The object should not be made visible to other threads, nor
should the final fields be read, until all updates to the
final fields of the object are complete. Freezes of a
final field occur both at the end of the constructor in
which the final field is set, and immediately after each
modification of a final field via reflection or other
special mechanism.
Even then, there are a number of
complications. If a final field is initialized to a
constant expression (15.29) in
the field declaration, changes to the final field may not
be observed, since uses of that final field are replaced at
compile time with the value of the constant expression.
Another problem is that the
specification allows aggressive optimization of final
fields. Within a thread, it is permissible to reorder reads of a
final field with those modifications of a
final field that do not take place in the constructor.
Example 17.5.3-1. Aggressive Optimization of final
Fields
class A {
final int x;
A() {
x = 1;
}
int f() {
return d(this,this);
}
int d(A a1, A a2) {
int i = a1.x;
g(a1);
int j = a2.x;
return j - i;
}
static void g(A a) {
// uses reflection to change a.x to 2
}
}
In the d method, the compiler is allowed to reorder the
reads of x and the call to g freely. Thus,
new A().f() could return -1, 0,
or 1.
...