This document describes changes to the Java Language
Specification, Java SE 22 Edition, as modified by Statements before
super(...)
, to support value classes and
objects, a preview feature introduced by JEP 401.
A companion documents describes JVM changes.
Key changes include:
Value objects as a new kind of object, with special behaviors for instantiation,
==
, and synchronizationA new
value
context-sensitive keyword for use as a class modifiersSpecial restrictions applied to value class declarations
In a value class, early execution of instance field initializers and the bodies of constructors that lack an explicit constructor invocation
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:
January 2024: dropped the
identity
keyword 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
float
anddouble
fields (4.3.1)August 2022: fixed rules about
synchronized
methods (8.1.1.5, 8.4.3.6) and binary compatibility ofidentity
/value
classes (13.4.1)May 2022: clarified that
identity
constrains the subclasses of a concrete class (8.1.1.5); added rules aboutabstract
inner classes (8.1.3) andabstract
classes 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
yield
is excluded from UnqualifiedMethodIdentifier, any invocation of a method namedyield
must be qualified, thus distinguishing the invocation from ayield
statement (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 16 17
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
module permits sealed var
non-sealed provides to with
open record transitive yield
value
The keywords
const
andgoto
are reserved, even though they are not currently used. This may allow a Java compiler to produce better error messages if these C++ keywords incorrectly appear in programs.
The keyword
strictfp
is obsolete and should not be used in new code.
The keyword
_
(underscore) is reserved for possible future use in parameter declarations.
true
andfalse
are not keywords, but rather boolean literals (3.10.3).
null
is 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
andopen
, 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
requires
transitive
;
does not make use of RequiresModifier, so the termtransitive
is 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
var
as an identifier will cause an error, becausevar
is not a TypeIdentifier (3.8).For
yield
, when recognized as a terminal in a YieldStatement (14.21).In other contexts, attempting to use the
yield
as an identifier will cause an error, becauseyield
is 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
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 c
is always tokenized as the identifierpublicstatic
, rather than as the reserved keywordspublic
andstatic
. 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 e
is usually tokenized as the identifiervarfilename
, but in a local variable declaration, the first three input characters are tentatively recognized as the contextual keywordvar
by 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 keywordvar
on the grounds that the immediately following input characterf
is a JavaLetterOrDigit. The sequencev a r f i l e n a m e
is therefore tokenized as the identifiervarfilename
in 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-sealed
andclass
) 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 s
is 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 the same as a previously-created object.
Two value objects are the same if they are instances of the
same class and the values of their instance fields are the same. For
fields of a floating-point primitive type, the field values are
considered the same if the results of the appropriate
Float.floatToRawIntBits
or
Double.doubleToRawLongBits
method are the same. For fields
of a reference type, the field values are considered the same if they
are both null
, or if they are references to the same object
(possibly applying this definition recursively).
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) are pointers to objects, and a 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 aString
operand and a reference, will convert the reference to aString
by invoking thetoString
method of the referenced object (using"null"
if either the reference or the result oftoString
is a null reference), and then will produce a newly createdString
that is the concatenation of the two stringsThe
instanceof
operator (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 8: Classes
8.1 Class Declarations
8.1.1 Class Modifiers
A class declaration may include class modifiers.
- ClassModifier:
- (one of)
-
Annotation
public
protected
private
-
abstract
static
final
sealed
non-sealed
strictfp
-
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.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.
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:
-
extends
ClassType
The extends
clause must not appear in the definition of
the class Object
, or a compile-time error occurs, because
it is the primordial class and has no direct superclass 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
Object
has no direct superclass type.For a class other than
Object
with a normal class declaration, the direct superclass type isObject
.For an enum class E, the direct superclass type is
Enum<
E>
.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).
In a value
class, a blank final
instance variable must be definitely assigned after the argument list of
an explicit superclass constructor invocation (8.8.7.1).
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 may also be 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
this
or 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
static
fields that are constant variables (4.12.4) are initialized before otherstatic
fields (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
) of a value class (8.1.1.5), then the initializer is an early
instance variable initializer and occurs in an early construction
context (8.8.7.1); the initializer may refer
to any class variable of the class, even one whose declaration occurs to
the right of the initializer. At run time, the initializer is evaluated
and the assignment performed each time an instance of the class is
created, at the start of the class's construction process (12.5).
If the declarator is for an instance variable (that is, a field
that is not of an identity
class, then static
)the following rules apply to its
initializer: the initializer is a late instance
variable initializer. The initializer may freely refer to the
current object using the keyword this
or the keyword
super
, and 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 may be 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, immediately after the superclass constructor
invocation (12.5).
The initializer may refer to the current object using the keyword
this
or 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).
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.3.3 Restrictions on Field References in Initializers
References to a field are sometimes restricted, even through the field is in scope. The following rules constrain forward references to a field (where the use textually precedes the field declaration) as well as self-reference (where the field is used in its own initializer).
For a reference by simple name to a class variable f declared in class or interface C, it is a compile-time error if:
The reference appears either in a class variable initializer of C or in a static initializer of C (8.7); and
The reference appears either in the initializer of f's own declarator or at a point to the left of f's declarator; and
The reference is not on the left hand side of an assignment expression (15.26); and
The innermost class or interface enclosing the reference is C.
For a reference by simple name to an instance variable f declared in class C, it is a compile-time error if:
The reference appears either in an instance variable initializer of C or in an instance initializer of C (8.6); and
If f has an early instance variable initializer (8.3.2), then the reference appears in the initializer of f's own declarator or in another early instance variable initializer to the left of f's declarator; and
TheIf f has a late instance variable initializer, then the reference appears in the initializer of f's own declarator or at a point to the left of f's declarator; andIf f has no initializer, then the reference appears at a point to the left of f's declarator; and
The reference is not on the left hand side of an assignment expression (15.26); and
The innermost class enclosing the reference is C.
Example 8.3.3-1. Restrictions on Field References
A compile-time error occurs for this program:
class Test1 {
int i = j; // compile-time error:
// incorrect forward reference
int j = 1;
}
whereas the following program compiles without error:
class Test2 {
Test2() { k = 2; }
int j = 1;
int i = j;
int k;
}
even though the constructor for Test2
(8.8)
refers to the field k
that is declared three lines
later.
The restrictions above are designed to catch, at compile time, circular or otherwise malformed initializations. Thus, both:
class Z {
static int i = j + 2;
static int j = 4;
}
and:
class Z {
static { i = j + 2; }
static int i, j;
static { j = 4; }
}
result in compile-time errors. Accesses by methods are not checked in this way, so:
class Z {
static int peek() { return j; }
static int i = peek();
static int j = 1;
}
class Test {
public static void main(String[] args) {
System.out.println(Z.i);
}
}
produces the output:
0
because the variable initializer for i
uses the class
method peek
to access the value of the variable
j
before j
has been initialized by its
variable initializer, at which point it still has its default value (4.12.5).
A more elaborate example is:
class UseBeforeDeclaration {
static {
x = 100;
// ok - assignment
int y = x + 1;
// error - read before declaration
int v = x = 3;
// ok - x at left hand side of assignment
int z = UseBeforeDeclaration.x * 2;
// ok - not accessed via simple name
Object o = new Object() {
void foo() { x++; }
// ok - occurs in a different class
{ x++; }
// ok - occurs in a different class
};
}
{
j = 200;
// ok - assignment
j = j + 1;
// error - right hand side reads before declaration
int k = j = j + 1;
// error - illegal forward reference to j
int n = j = 300;
// ok - j at left hand side of assignment
int h = j++;
// error - read before declaration
int l = this.j * 3;
// ok - not accessed via simple name
Object o = new Object() {
void foo(){ j++; }
// ok - occurs in a different class
{ j = j + 1; }
// ok - occurs in a different class
};
}
int w = x = 3;
// ok - x at left hand side of assignment
int p = x;
// ok - instance initializers may access static fields
static int u =
(new Object() { int bar() { return x; } }).bar();
// ok - occurs in a different class
static int x;
int m = j = 4;
// ok - j at left hand side of assignment
int o =
(new Object() { int bar() { return j; } }).bar();
// ok - occurs in a different class
int j;
}
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]}
-
{
[BlockStatements] ExplicitConstructorInvocation [BlockStatements]}
If a constructor body contains an explicit constructor invocation,
the BlockStatements preceding the explicit constructor
invocation are called the prologue of the constructor body. The
BlockStatements in a constructor with no explicit
constructor invocation and the BlockStatements following
an explicit constructor invocation in a constructor body are called the
epilogue.
If the body of a constructor in a value class (8.1.1.5) 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 identity 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 implicitly begins with a superclass constructor invocation
"super();
", an invocation of the constructor of the direct
superclass that takes no arguments.
A return
statement (14.17)
may be used in the epilogue of a constructor body if it does not include
an expression. It is a compile-time error if a return
statement appears in the prologue of a constructor body.
Except for the possibility of explicit or implicit constructor
invocations, and the prohibitions 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 explicit constructor invocation. The grammar makes it impossible, for example, to place explicit constructor invocations in different branches of an
if
statement.
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 Explicit Constructor Invocations
- ExplicitConstructorInvocation:
-
[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}
Explicit 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.
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).
The rules for a superclass constructor invocation, where C is the class being instantiated, and S is the direct superclass of C, are as follows:
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 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 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.
An expression occurs in the early construction context of a class C if both of the following are true:
The innermost method declaration, field declaration, constructor declaration, instance initializer, or static initializer which encloses the expression is
the declaration ofeither a constructor declaration or an early instance field initializer (8.3.2),cd, of class C; andIf d is a constructor declaration,
Thethen the expression is contained in a statement in the prologue of the body ofcd or is enclosed in an explicit constructor invocation in the body ofcd.
An expression is said to occur in an early construction context if it occurs in the early construction context of some class without being specific about which class.
Expressions that occur in the early construction context of a class C are restricted in the following ways:
all unqualified
this
expressions (15.8.3) and any qualifiedthis
expression whose qualifier names the class C are disallowed (15.8.4), except as the qualifier of a permitted instance variable reference in an assignment.Field accesses, method invocations, and method references may not be qualified by
super
(15.11.2, 15.12.3, 15.13.1).References to instance variables of class C are disallowed, except in an assignment to an instance variable of C whose declaration lacks an initializer (6.5.6.1).
Invocations of instance methods of class C are disallowed (15.12.3).
Class instance creation expressions that instantiate inner classes may not have immediately enclosing instances of class C (15.9.2).
These restrictions are a subset of the restrictions on an expression that occurs in a static context. Unlike in a static context, an expression in an early construction context is free, for example, to refer to the type of the instance under construction.
...
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}
enum
TypeIdentifier [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
final
if its declaration contains no enum constants that have a class body (8.9.1).An enum class E is implicitly
sealed
if 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
extends
clause, 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
final
clone
method inEnum
ensures 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}
record
TypeIdentifier [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
value
class, because its instance fields are alwaysfinal
and its implicitly declaredequals
method 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
extends
clause, 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).
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
String
object to denote the string represented by the string literal or text block. (This object creation will not occur if an instance ofString
denoting 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 newString
object 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
class's constructor, its assignment occurs in
Step 3 of the object initialization procedure, before evaluation of the
Super
class's constructor body 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.
If a value
class is changed to be an identity class,
then an IncompatibleClassChangeError
is thrown if a binary
of a pre-existing value
subclass of this class is loaded,
because value
classes cannot extend identity classes (8.1.4); such a change is not recommended for
widely distributed classes.
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
synchronized
statement completes abruptly for the same reason.Otherwise, if the value of the Expression is
null
, aNullPointerException
is thrown.Otherwise, if the value of the Expression is a reference to a value object, an
IllegalMonitorStateException
is thrown.Otherwise, let the non-
null
value 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
synchronized
statement completes normally.If execution of the Block completes abruptly for any reason, then the monitor is unlocked and the
synchronized
statement 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.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 invocation statements (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-
final
is 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 anextends
clause) 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
object or array (4.3.1);
otherwise, the result is false
.
The result of !=
is false
if the operand
values are both null
or both refer to the same object or
array; 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)
.
Chapter 16: Definite Assignment
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 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,and V is definitely assigned after every superclass constructor invocation inthese constructorsthe constructors of C, and 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.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 unassigned) before the constructor declaration or instance variable initializer.
The following rules hold within the constructors (8.8.7) of class C:
A blank
final
non-static
member 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 an explicit 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 explicit constructor invocation iff V is [un]assigned before the invocation.
V is [un]assigned after the argument list of an explicit 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
final
non-static
member 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
final
non-static
member 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
final
non-static
member 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
final
non-static
member 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
final
non-static
member 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.