This document describes changes to the Java Language Specification, Java SE 23 Edition, as modified by Flexible Constructor Bodies, to support value classes and objects, a preview feature introduced by JEP 401.
Related documents: JVM Changes • Flexible Constructor Bodies
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 modifierSpecial 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:
November 2024: addressed handling of value classes in the standard libraries (1.5), including the behavior of boxing (5.1.7); prohibited using
sealed
andnon-sealed
with non-abstract
value 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
synchronized
statement toIdentityException
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 1: Introduction
1.5 Preview Features
A preview feature is:
a new feature of the Java programming language ("preview language feature"), or
a new module, package, class, interface, field, method, constructor, or enum constant in the
java.*
orjavax.*
namespace ("preview API")
that is fully specified, fully implemented, and yet impermanent. It is available in implementations of a given release of the Java SE Platform to provoke developer feedback based on real world use; this may lead to it becoming permanent in a future release of the Java SE Platform.
Implementations must disable, at both compile time and run time, the preview features defined by a given release of the Java SE Platform, unless the user indicates via the host system, at both compile time and run time, that preview features are to be enabled.
The preview features defined by a given release of the Java SE Platform are enumerated in the Java SE Platform Specification for that release. The preview features are specified as follows:
Preview language features are specified in standalone documents that indicate changes ("diffs") to The Java® Language Specification for that release. The specifications of preview language features are incorporated into The Java® Language Specification by reference, and made a part thereof, if and only if preview features are enabled at compile time.
Java SE 24 defines four preview language features: Flexible Constructor Bodies; Simple Source Files and Instance
main
Methods; Module Import Declarations; and Primitive Types in Patterns,instanceof
, andswitch
. The standalone documents which specify these preview features are available at the web site which hosts this edition of The Java® Language Specification.Preview APIs are specified within the Java SE API Specification for that release.
When preview features are enabled, a number of existing classes in the
java.base
module, includingInteger
andjava.util.Optional
, are considered to be value classes (8.1.1.5), even though these classes cannot be declared as preview APIs. The API specifications for these classes indicate this special behavior.
The rules for use of preview language features are as follows:
If preview features are disabled, then any source code reference to a preview language feature, or to a class or interface declared using a preview language feature, causes a compile-time error.
If preview features are enabled, then any source code reference to a class or interface declared using a preview language feature causes a preview warning, unless one of the following is true:
The reference appears in a declaration that is annotated to suppress preview warnings ([9.6.4.5]).
The reference appears in an import declaration ([7.5]).
When preview features are enabled, Java compilers are strongly encouraged to give a non-suppressible warning for every source code reference to a preview language feature. Details of this warning are beyond the scope of this specification, but the intent should be to alert programmers to the possibility of code being affected by future changes to preview language features.
Some preview APIs are described as
reflective by the Java SE Platform Specification, principally
in the java.lang.reflect
, java.lang.invoke
,
and javax.lang.model
packages. The rule for use of
reflective preview APIs is as follows:
Whether preview features are enabled or disabled, any source code reference to a reflective preview API element causes a preview warning, unless one of the following is true:
The declaration where the reference appears is within the same module as the declaration of the reflective preview API element.
The reference appears in a declaration that is annotated to suppress preview warnings.
The reference appears in an import declaration.
All preview APIs not described as reflective in the Java SE Platform Specification are normal. The rules for use of normal preview APIs are as follows:
If preview features are disabled, then any source code reference to a normal preview API element causes a compile-time error, unless:
- The declaration where the reference appears is within the same module as the declaration of the normal preview API element.
If preview features are enabled, then any source code reference to a normal preview API element causes a preview warning, unless one of the following is true:
The declaration where the reference appears is within the same module as the declaration of the normal preview API element.
The reference appears in a declaration that is annotated to suppress preview warnings.
The reference appears in an import declaration.
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 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
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) may be used in certain declarations in place of an identifier ([6.1]).
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
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 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 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 the Float.floatToRawIntBits
or
Double.doubleToRawLongBits
operation). For reference-typed
instance fields, this means the field values are both references to the
same object (possibly applying this definition recursively), or are both
null
.
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 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 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
boolean
to typeBoolean
From type
byte
to typeByte
From type
short
to typeShort
From type
char
to typeCharacter
From type
int
to typeInteger
From type
long
to typeLong
From type
float
to typeFloat
From type
double
to typeDouble
From 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() == p
If p is a value of type
byte
, then boxing conversion converts p into a reference r of class and typeByte
, such thatr.byteValue() == p
If p is a value of type
char
, then boxing conversion converts p into a reference r of class and typeCharacter
, such thatr.charValue() == p
If p is a value of type
short
, then boxing conversion converts p into a reference r of class and typeShort
, such thatr.shortValue() == p
If p is a value of type
int
, then boxing conversion converts p into a reference r of class and typeInteger
, such thatr.intValue() == p
If p is a value of type
long
, then boxing conversion converts p into a reference r of class and typeLong
, such thatr.longValue() == p
If p is a value of type
float
then: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
Float
such 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
Double
such 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
char
andshort
values, as well asint
andlong
values in the range of -32K to +32K.
If
a
andb
are 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 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.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
sealed
in 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
sealed
keyword 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
final
or implicitlysealed
, so it can implement asealed
interface. Similarly,a record class isrecord classes and non-abstract
value 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-sealed
class 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:
-
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 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).
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.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 prologue of a constructor body may be empty.
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. The epilogue of a constructor body may also be
empty.
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.
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 it is contained
in either one of the prologue of a
constructor body of C, or it is nested in the
explicit constructor invocation of a constructor body of
C, or an early instance field initializer (8.3.2) of C.
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).
...
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.
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
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
IdentityException
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)
.
As outlined in 4.3.1, an identity object is only ever the same as itself, while a value object is the same as all instances of the same class with the same field values.
A common mistake is to use the
==
operator to test for the same object, when what is usually wanted is more abstract, testing whether two objects model the same value or entity. Theequals
method serves this purpose, allowing classes to declare an appropriate domain-specific notion of equality.For example, two distinct
String
objects,s
andt
, may contain the same sequence of characters. A comparison of these objects usings == t
will 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
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 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.
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.