This document describes changes to the Java Language Specification
to support Statements before super()
, which is a
proposed feature of Java SE 21. See JEP 447 for an overview of the
feature.
Changes are described with respect to existing sections of the JLS.
New text is indicated like this and deleted text is
indicated like this. Explanation and discussion, as needed,
is set aside in grey boxes.
2023-04-20: First draft
Chapter 6: Names
6.5 Determining the Meaning of a Name
6.5.6 Meaning of Expression Names
6.5.6.1 Simple Expression Names
If an expression name consists of a single Identifier, then there must be exactly one declaration denoting either a local variable, formal parameter, exception parameter, or field in scope at the point at which the identifier occurs. Otherwise, a compile-time error occurs.
If the declaration denotes an instance variable of a class C (8.3.1.1), then both of the following must be true, or a compile-time error occurs:
The expression name does not occur in a static context (8.1.3), or in a pre-initialization context of the associated instance (8.8.7.1).
If the expression name appears in a nested class or interface declaration of C, then the immediately enclosing class or interface declaration of the expression name is an inner class of C.
For example, the expression name must not appear in the body of a
static
method declared by C, nor in the body of an instance method of astatic
class nested within C.
If the declaration denotes a local variable, formal parameter, or exception parameter, let X be the innermost method declaration, constructor declaration, instance initializer, static initializer, field declaration, or explicit constructor invocation statement which encloses the local variable or parameter declaration. If the expression name appears directly or indirectly in the body of a local class, local interface, or anonymous class D declared directly in X, then both of the following must be true, or a compile-time error occurs:
The expression name does not occur in a static context.
D is an inner class, and the immediately enclosing class or interface declaration of the expression name is D or an inner class of D.
For example, the expression name must not appear in the body of a
static
method declared by D, nor (if D is a local interface) in the body of a default method of D.
If the declaration denotes a local variable, formal parameter, or
exception parameter that is neither final
nor effectively
final (4.12.4),
it is a compile-time error if the expression name appears either in an
inner class enclosed directly or indirectly by X, or in a
lambda expression contained by X (15.27).
The net effect of these rules is that a local variable, formal parameter, or exception parameter can only be referenced from a nested class or interface declared within its scope if (i) the reference is not within a static context, (ii) there is a chain of inner (non-
static
) classes from the reference to the variable declaration, and (iii) the variable isfinal
or effectively final. References from lambda expressions also require the variable to befinal
or effectively final.
If the declaration declares a final
variable which is
definitely assigned before the simple expression, the meaning of the
name is the value of that variable. Otherwise, the meaning of the
expression name is the variable declared by the declaration.
If the expression name appears in an assignment context, invocation context, or casting context, then the type of the expression name is the declared type of the field, local variable, or parameter after capture conversion (5.1.10).
Otherwise, the type of the expression name is the declared type of the field, local variable or parameter.
That is, if the expression name appears "on the right hand side", its type is subject to capture conversion. If the expression name is a variable that appears "on the left hand side", its type is not subject to capture conversion.
Example 6.5.6.1-1. Simple Expression Names
class Test {
static int v;
static final int f = 3;
public static void main(String[] args) {
int i;
i = 1;
v = 2;
f = 33; // compile-time error
System.out.println(i + " " + v + " " + f);
}
}
In this program, the names used as the left-hand-sides in the
assignments to i
, v
, and f
denote
the local variable i
, the field v
, and the
value of f
(not the variable f
, because
f
is a final
variable). The example therefore
produces an error at compile time because the last assignment does not
have a variable as its left-hand side. If the erroneous assignment is
removed, the modified code can be compiled and it will produce the
output:
1 2 3
Example 6.5.6.1-2. References to Instance Variables
class Test {
static String a;
String b;
String concat1() {
return a + b;
}
static String concat2() {
return a + b; // compile-time error
}
int index() {
interface I {
class Matcher {
void check() {
if (a == null ||
b == null) { // compile-time error
throw new IllegalArgumentException();
}
}
int match(String s, String t) {
return s.indexOf(t);
}
}
}
I.Matcher matcher = new I.Matcher();
matcher.check();
return matcher.match(a, b);
}
}
The fields a
and b
are in scope throughout
the body of class Test
. However, using the name
b
in the static context of the concat2
method,
or in the declaration of the nested class Matcher
that is
not an inner class of Test
, is illegal.
Example 6.5.6.1-3. References to Local Variables and Formal Parameters
class Test {
public static void main(String[] args) {
String first = args[0];
class Checker {
void checkWhitespace(int x) {
String arg = args[x];
if (!arg.trim().equals(arg)) {
throw new IllegalArgumentException();
}
}
static void checkFlag(int x) {
String arg = args[x]; // compile-time error
if (!arg.startsWith("-")) {
throw new IllegalArgumentException();
}
}
static void checkFirst() {
Runnable r = new Runnable() {
public void run() {
if (first == null) { // compile-time error
throw new IllegalArgumentException();
}
}
};
r.run();
}
}
final Checker c = new Checker();
c.checkFirst();
for (int i = 1; i < args.length; i++) {
Runnable r = () -> {
c.checkWhitespace(i); // compile-time error
c.checkFlag(i); // compile-time error
};
}
}
}
The formal parameter args
is in scope throughout the
body of method main
. args
is effectively
final, so the name args
can be used in the instance method
checkWhitespace
of local class Checker
.
However, using the name args
in the static context of the
checkFlag
method of local class Checker
is
illegal.
The local variable first
is in scope for the remainder
of the body of method main
. first
is also
effectively final. However, the anonymous class declared in
checkFirst
is not an inner class of Checker
,
so using the name first
in the anonymous class body is
illegal. (A lambda expression in the body of checkFirst
would similarly be unable to refer to first
, because the
lambda expression would occur in a static context.)
The local variable c
is in scope for the last few lines
of the body of method main
, and is declared
final
, so the name c
can be used in the body
of the lambda expression.
The local variable i
is in scope throughout the
for
loop. However, i
is not effectively final,
so using the name i
in the body of the lambda expression is
illegal.
6.5.7 Meaning of Method Names
6.5.7.1 Simple Method Names
A simple method name appears in the context of a method invocation expression (15.12). The simple method name consists of a single UnqualifiedMethodIdentifier which specifies the name of the method to be invoked. The rules of method invocation require that the UnqualifiedMethodIdentifier denotes a method that is in scope at the point of the method invocation. The rules also prohibit (15.12.3) a reference to an instance method occurring in a static context (8.1.3), a pre-initialization context of the associated instance (8.8.7.1), or in a nested class or interface other than an inner class of the class or interface which declares the instance method.
Example 6.5.7.1-1. Simple Method Names
The following program demonstrates the role of scoping when determining which method to invoke.
class Super {
void f2(String s) {}
void f3(String s) {}
void f3(int i1, int i2) {}
}
class Test {
void f1(int i) {}
void f2(int i) {}
void f3(int i) {}
void m() {
new Super() {
{
f1(0); // OK, resolves to Test.f1(int)
f2(0); // compile-time error
f3(0); // compile-time error
}
};
}
}
For the invocation f1(0)
, only one method named
f1
is in scope. It is the method Test.f1(int)
,
whose declaration is in scope throughout the body of Test
including the anonymous class declaration. 15.12.1
chooses to search in class Test
since the anonymous class
declaration has no member named f1
. Eventually,
Test.f1(int)
is resolved.
For the invocation f2(0)
, two methods named
f2
are in scope. First, the declaration of the method
Super.f2(String)
is in scope throughout the anonymous class
declaration. Second, the declaration of the method
Test.f2(int)
is in scope throughout the body of
Test
including the anonymous class declaration. (Note that
neither declaration shadows the other, because at the point where each
is declared, the other is not in scope.) 15.12.1
chooses to search in class Super
because it has a member
named f2
. However, Super.f2(String)
is not
applicable to f2(0)
, so a compile-time error occurs. Note
that class Test
is not searched.
For the invocation f3(0)
, three methods named
f3
are in scope. First and second, the declarations of the
methods Super.f3(String)
and Super.f3(int,int)
are in scope throughout the anonymous class declaration. Third, the
declaration of the method Test.f3(int)
is in scope
throughout the body of Test
including the anonymous class
declaration. 15.12.1
chooses to search in class Super
because it has a member
named f3
. However, Super.f3(String)
and
Super.f3(int,int)
are not applicable to f3(0)
,
so a compile-time error occurs. Note that class Test
is not
searched.
Choosing to search a nested class's superclass hierarchy before the lexically enclosing scope is called the "comb rule" (15.12.1).
Chapter 8: Classes
8.1 Class Declarations
8.1.3 Inner Classes and Enclosing Instances
An inner class is a nested class that is not explicitly or
implicitly static
.
An inner class is one of the following:
a member class that is not explicitly or implicitly
static
(8.5)a local class that is not implicitly
static
(14.3)an anonymous class (15.9.5)
The following nested classes are implicitly static
, so
are not inner classes:
- a member enum class (8.9)
- a local enum class (14.3)
- a member record class (8.10)
- a local record class (14.3)
- a member class of an interface (9.5)
All of the rules that apply to nested classes apply to inner classes.
In particular, an inner class may declare and inherit
static
members (8.2),
and declare static initializers (8.7),
even though the inner class itself is not static
.
There are no "inner interfaces" because every nested interface is implicitly
static
(9.1.1.3).
Example 8.1.3-1. Inner Class Declarations and Static Members
class HasStatic {
static int j = 100;
}
class Outer {
class Inner extends HasStatic {
static {
System.out.println("Hello from Outer.Inner");
}
static int x = 3;
static final int y = 4;
static void hello() {
System.out.println("Hello from Outer.Inner.hello");
}
static class VeryNestedButNotInner
extends NestedButNotInner {}
}
static class NestedButNotInner {
int z = Inner.x;
}
interface NeverInner {} // Implicitly static, so never inner
}
Prior to Java SE 16, an inner class could not declare static
initializers, and could only declare static
members that
were constant variables (4.12.4).
A construct (statement, local variable declaration statement, local class declaration, local interface declaration, or expression) occurs in a static context if the innermost:
method declaration,
field declaration,
constructor declaration,
instance initializer, or
static initializer
, orexplicit constructor invocation statement
which encloses the construct is one of the following:
Note that a construct which appears in a constructor declaration or an instance initializer does not occur in a static context.
The purpose of a static context is to demarcate code that must not refer explicitly or implicitly to the current instance of the class whose declaration lexically encloses the static context.The purpose of a static context is to demarcate code for which there is no current instance defined of the class whose declaration lexically encloses the static context. Consequently, code that occurs in a static context is restricted in the following ways:
this
expressions (both unqualified and qualified) are disallowed (15.8.3, 15.8.4).Field accesses, method invocations, and method references may not be qualified by
super
(15.11.2, 15.12.3, 15.13.1).Unqualified references to instance variables of any lexically enclosing class or interface declaration are disallowed (6.5.6.1).
Unqualified invocations of instance methods of any lexically enclosing class or interface declaration are disallowed (15.12.3).
References to type parameters of any lexically enclosing class or interface declarations are disallowed (6.5.5.1).
References to type parameters, local variables, formal parameters, and exception parameters declared by methods or constructors of any lexically enclosing class or interface declaration that is outside the immediately enclosing class or interface declaration are disallowed (6.5.5.1, 6.5.6.1).
Declarations of local normal classes (as opposed to local enum classes) and declarations of anonymous classes both specify classes that are inner, yet when instantiated have no immediately enclosing instances (15.9.2).
Class instance creation expressions that instantiate inner member classes must be qualified (15.9).
An inner class C is a direct inner class of a class or interface O if O is the immediately enclosing class or interface declaration of C and the declaration of C does not occur in a static context.
If an inner class is a local class or an anonymous class, it may be declared in a static context, and in that case is not considered an inner class of any enclosing class or interface.
A class C is an inner class of class or interface O if it is either a direct inner class of O or an inner class of an inner class of O.
It is unusual, but possible, for the immediately enclosing class or interface declaration of an inner class to be an interface. This only occurs if the class is a local or anonymous class declared in a
default
orstatic
method body (9.4).
A class or interface O is the zeroth lexically enclosing class or interface declaration of itself.
A class O is the n'th lexically enclosing class declaration of a class C if it is the immediately enclosing class declaration of the n-1'th lexically enclosing class declaration of C.
An instance i of a direct inner class C of a class or interface O is associated with an instance of O, known as the immediately enclosing instance of i. The immediately enclosing instance of an object, if any, is determined when the object is created (15.9.2).
An object o is the zeroth lexically enclosing instance of itself.
An object o is the n'th lexically enclosing instance of an instance i if it is the immediately enclosing instance of the n-1'th lexically enclosing instance of i.
An instance of an inner local class or an anonymous class whose
declaration occurs in a static context has no immediately enclosing
instance. Also, an instance of a static
nested class (8.1.1.4)
has no immediately enclosing instance.
For every superclass S of C which is itself a direct inner class of a class or interface SO, there is an instance of SO associated with i, known as the immediately enclosing instance of i with respect to S. The immediately enclosing instance of an object with respect to its class' direct superclass, if any, is determined when the superclass constructor is invoked via an explicit constructor invocation statement (8.8.7.1).
When an inner class (whose declaration does not occur in a static context) refers to an instance variable that is a member of a lexically enclosing class or interface declaration, the variable of the corresponding lexically enclosing instance is used.
Any local variable, formal parameter, or exception parameter used but
not declared in an inner class must either be final
or
effectively final (4.12.4),
as specified in 6.5.6.1.
Any local variable used but not declared in an inner class must be definitely assigned (16) before the body of the inner class, or a compile-time error occurs.
Similar rules on variable use apply in the body of a lambda expression (15.27.2).
A blank final
field (4.12.4)
of a lexically enclosing class or interface declaration may not be
assigned within an inner class, or a compile-time error occurs.
Example 8.1.3-2. Inner Class Declarations
class Outer {
int i = 100;
static void classMethod() {
final int l = 200;
class LocalInStaticContext {
int k = i; // Compile-time error
int m = l; // OK
}
}
void foo() {
class Local { // A local class
int j = i;
}
}
}
The declaration of class LocalInStaticContext
occurs in
a static context due to being within the static method
classMethod
. Instance variables of class Outer
are not available within the body of a static method. In particular,
instance variables of Outer
are not available inside the
body of LocalInStaticContext
. However, local variables from
the surrounding method may be referred to without error (provided they
are declared final
or are effectively final).
Inner classes whose declarations do not occur in a static context may
freely refer to the instance variables of their enclosing class
declaration. An instance variable is always defined with respect to an
instance. In the case of instance variables of an enclosing class
declaration, the instance variable must be defined with respect to an
enclosing instance of the inner class. For example, the class
Local
above has an enclosing instance of class
Outer
. As a further example:
class WithDeepNesting {
boolean toBe;
WithDeepNesting(boolean b) { toBe = b; }
class Nested {
boolean theQuestion;
class DeeplyNested {
DeeplyNested(){
theQuestion = toBe || !toBe;
}
}
}
}
Here, every instance of
WithDeepNesting.Nested.DeeplyNested
has an enclosing
instance of class WithDeepNesting.Nested
(its immediately
enclosing instance) and an enclosing instance of class
WithDeepNesting
(its 2nd lexically enclosing instance).
8.8 Constructor Declarations
8.8.7 Constructor Body
The first statement of a constructor body may be an explicit
invocation of another constructor of the same class or of the direct
superclass (8.8.7.1).
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:
-
{
[ExplicitConstructorInvocation] [BlockStatements]}
-
{
[BlockStatements]}
-
{
[BlockStatements] [ExplicitConstructorInvocation] [BlockStatements]}
It is a compile-time error for a constructor to directly or
indirectly invoke itself through a series of one or more explicit
constructor invocations involving this
.
If a constructor body does not begin with
contain an explicit constructor invocation and 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 its direct superclass that takes no arguments.
Except for the possibility of explicit constructor invocations, and
the prohibition on explicitly returning a value
prohibitions on return
statements (14.17),
the body of a constructor is like the body of a method (8.4.7).
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
the explicit constructor invocation in a constructor with an explicit
constructor invocation are called the main body of the
constructor.
A return
statement (14.17)
may be used in the main body of a constructor 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.
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 invocation statements 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.
An explicit constructor invocation statement introduces a static
context (8.1.3), which limits the use of
constructs that refer to the current object. Notably, the keywords
this
and super
are prohibited in a static
context (15.8.3, 15.11.2), as are unqualified references to
instance variables, instance methods, and type parameters of lexically
enclosing declarations (6.5.5.1,
6.5.6.1, 15.12.3).
An explicit constructor invocation statement introduces a
pre-initialization context of the current object. The
pre-initialization context includes the prologue of the constructor (8.8.7) and the explicit constructor invocation
statement itself. Within a pre-initialization context, constructs that
refer explicitly or implicitly to the current object are disallowed.
These include this
or super
expressions
referring to the current object, unqualified references to instance
variables or instance methods of the current object, method references
referring to instance methods of the current object, and instantiations
of inner classes of the current object's class for which the current
object is the enclosing instance (8.1.3).
If TypeArguments is present to the left of this
or super
, then it is a compile-time error if any of the
type arguments are wildcards (4.5.1).
Let C be the class being instantiated, and let S be the direct superclass of C.
If a superclass constructor invocation statement 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 statement 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 statement can throw are specified in 11.2.2.
Evaluation of an alternate constructor invocation statement proceeds by first evaluating the arguments to the constructor, left-to-right, as in an ordinary method invocation; and then invoking the constructor.
Evaluation of a superclass constructor invocation statement proceeds as follows:
Let i be the instance being created. The immediately enclosing instance of i with respect to S (if any) must be determined:
If S is not an inner class, or if the declaration of S occurs in a static context, then no immediately enclosing instance of i with respect to S exists.
Otherwise, if the superclass constructor invocation is unqualified, then S is necessarily an inner local class or an inner member class.
If S is an inner local class, let O be the immediately enclosing class or interface declaration of S.
If S is an inner member class, let O be the innermost enclosing class of C of which S is a member.
Let n be an integer (n ≥ 1) such that O is the n'th lexically enclosing class or interface declaration of C.
The immediately enclosing instance of i with respect to S is the n'th lexically enclosing instance of
this
.While it may be the case that S is a member of C due to inheritance, the zeroth lexically enclosing instance of
this
(that is,this
itself) is never used as the immediately enclosing instance of i with respect to S.Otherwise, if the superclass constructor invocation is qualified, then the Primary expression or the ExpressionName immediately preceding "
.super
", p, is evaluated.If p evaluates to
null
, aNullPointerException
is raised, and the superclass constructor invocation completes abruptly.Otherwise, the result of this evaluation is the immediately enclosing instance of i with respect to S.
After determining the immediately enclosing instance of i with respect to S (if any), evaluation of the superclass constructor invocation statement proceeds by evaluating the arguments to the constructor, left-to-right, as in an ordinary method invocation; and then invoking the constructor.
Finally, if the superclass constructor invocation statement completes normally, then all instance variable initializers of C and all instance initializers of C are executed. If an instance initializer or instance variable initializer I textually precedes another instance initializer or instance variable initializer J, then I is executed before J.
Execution of instance variable initializers and instance initializers is performed regardless of whether the superclass constructor invocation actually appears as an explicit constructor invocation statement or is provided implicitly. (An alternate constructor invocation does not perform this additional implicit execution.)
Example 8.8.7.1-1. Restrictions on Explicit Constructor Invocation Statements
If the first constructor of ColoredPoint
in the example
from 8.8.7 were changed as follows:
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, color); // Changed to color from WHITE
}
ColoredPoint(int x, int y, int color) {
super(x, y);
this.color = color;
}
}
then a compile-time error would occur, because the instance variable
color
cannot be used by a explicit constructor invocation
statement.
Example 8.8.7.1-2. Qualified Superclass Constructor Invocation
In the code below, ChildOfInner
has no lexically
enclosing class or interface declaration, so an instance of
ChildOfInner
has no enclosing instance. However, the
superclass of ChildOfInner
(Inner
) has a
lexically enclosing class declaration (Outer
), and an
instance of Inner
must have an enclosing instance of
Outer
. The enclosing instance of Outer
is set
when an instance of Inner
is created. Therefore, when we
create an instance of ChildOfInner
, which is implicitly an
instance of Inner
, we must provide the enclosing instance
of Outer
via a qualified superclass invocation statement in
ChildOfInner
's constructor. The instance of
Outer
is called the immediately enclosing instance of
ChildOfInner
with respect to Inner
.
class Outer {
class Inner {}
}
class ChildOfInner extends Outer.Inner {
ChildOfInner() { (new Outer()).super(); }
}
Perhaps surprisingly, the same instance of Outer
may
serve as the immediately enclosing instance of ChildOfInner
with respect to Inner
for multiple instances of
ChildOfInner
. These instances of
ChildOfInner
are implicitly linked to the same instance of
Outer
. The program below achieves this by passing an
instance of Outer
to the constructor of
ChildOfInner
, which uses the instance in a qualified
superclass constructor invocation statement. The rules for an explicit
constructor invocation statement do not prohibit using formal parameters
of the constructor that contains the statement.
class Outer {
int secret = 5;
class Inner {
int getSecret() { return secret; }
void setSecret(int s) { secret = s; }
}
}
class ChildOfInner extends Outer.Inner {
ChildOfInner(Outer x) { x.super(); }
}
public class Test {
public static void main(String[] args) {
Outer x = new Outer();
ChildOfInner a = new ChildOfInner(x);
ChildOfInner b = new ChildOfInner(x);
System.out.println(b.getSecret());
a.setSecret(6);
System.out.println(b.getSecret());
}
}
This program produces the output:
5
6
The effect is that manipulation of instance variables in the common
instance of Outer
is visible through references to
different instances of ChildOfInner
, even though such
references are not aliases in the conventional sense.
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 begins with an explicit constructor invocation (8.8.7.1) of another constructor in the same class (usingIf this constructor contains an explicit constructor invocation (8.8.7.1), then execute thethis
), then evaluate the arguments and process that constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason; otherwise, continue with step 5.BlockStatements
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 step 3.If this constructor contains an explicit constructor invocation (8.8.7.1) of another constructor in the same class (using
this
), then evaluate the arguments and process that constructor invocation recursively using these same six steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason; otherwise, continue with step 6.This constructor does not
begin withcontain an explicit constructor invocation of another constructor in the same class (usingthis
). If this constructor is for a class other thanObject
, then this constructorwill begin withcontains an explicit or implicit invocation of a superclass constructor (usingsuper
). Evaluate the arguments and process that superclass constructor invocation recursively using these samefivesix steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, continue with step45.4.Execute the instance initializers and 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 step56.5.Execute therest of themain body of this constructor. If that execution 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.
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 rest of the
body of the ColoredPoint
constructor is executed (the part
after the invocation of super
); there happen to be no
statements in the rest of the body, 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.
Chapter 15: Expressions
15.8 Primary Expressions
15.8.3 this
The keyword this
may be used as an expression in the
following contexts:
in the body of an instance method of a class (8.4.3.2)
in the main body of a constructor of a class (8.8.7)
in an instance initializer of a class (8.6)
in the initializer of an instance variable of a class (8.3.2)
in the body of an instance method of an interface, that is, a default method or a non-
static
private
interface method (9.4)
When used as an expression, the keyword this
denotes a
value that is a reference either to the object for which the instance
method was invoked (15.12),
or to the object being constructed. The value denoted by
this
in a lambda body (15.27.2)
is the same as the value denoted by this
in the surrounding
context.
The keyword
this
is also used in explicit constructor invocation statements (8.8.7.1), and to denote the receiver parameter of a method or constructor (8.4).
It is a compile-time error if a this
expression occurs
in a static context (8.1.3) or in a
pre-initialization context of the associated instance (8.8.7.1).
Let C by the innermost enclosing class or interface
declaration of a this
expression. If C is generic,
with type parameters F1,...,Fn,
the type of this
is
C<
F1,...,Fn>
.
Otherwise, the type of this
is C.
At run time, the class of the actual object referred to may be C or a subclass of C (8.1.5.
Example 15.8.3-1. The this
Expression
class IntVector {
int[] v;
boolean equals(IntVector other) {
if (this == other)
return true;
if (v.length != other.v.length)
return false;
for (int i = 0; i < v.length; i++) {
if (v[i] != other.v[i]) return false;
}
return true;
}
}
Here, the class IntVector
implements a method
equals
, which compares two vectors. If the other vector is
the same vector object as the one for which the equals
method was invoked, then the check can skip the length and value
comparisons. The equals
method implements this check by
comparing the reference to the other object to this
.
15.11 Field Access Expressions
15.11.2 Accessing Superclass Members using
super
The form super.
Identifier refers to the field
named Identifier of the current object, but with the current
object viewed as an instance of the superclass of the current class.
The form T.super.
Identifier refers to
the field named Identifier of the lexically enclosing instance
corresponding to T, but with that instance viewed as an
instance of the superclass of T.
The forms using the keyword super
may be used in the
locations within a class declaration that allow the keyword
this
as an expression (15.8.3).
It is a compile-time error if a field access expression using the
keyword super
appears in a static context (8.1.3) or in a pre-initialization context
of the associated instance (8.8.7.1).
For a field access expression of the form
super.
Identifier:
- It is a compile-time error if the immediately enclosing class or
interface declaration of the field access expression is the class
Object
or an interface.
For a field access expression of the form
T.super.
Identifier:
It is a compile-time error if T is the class
Object
or an interface.Let U be the immediately enclosing class or interface declaration of the field access expression. It is a compile-time error if U is not an inner class of T or T itself.
Suppose that a field access expression super.
f
appears within class C, and the immediate superclass of
C is class S. If f in S is
accessible from class C (6.6),
then super.
f is treated as if it had been the
expression this.
f in the body of class S.
Otherwise, a compile-time error occurs.
Thus,
super.
f can access the field f that is accessible in class S, even if that field is hidden by a declaration of a field f in class C.
Suppose that a field access expression
T.super.
f appears within class
C, and the immediate superclass of the class denoted by
T is a class whose fully qualified name is S. If
f in S is accessible from C, then
T.super.
f is treated as if it had been
the expression this.
f in the body of class
S. Otherwise, a compile-time error occurs.
Thus, T
.super.
f can access the field f that is accessible in class S, even if that field is hidden by a declaration of a field f in class T.
Example 15.11.2-1. The super
Expression
interface I { int x = 0; }
class T1 implements I { int x = 1; }
class T2 extends T1 { int x = 2; }
class T3 extends T2 {
int x = 3;
void test() {
System.out.println("x=\t\t" + x);
System.out.println("super.x=\t\t" + super.x);
System.out.println("((T2)this).x=\t" + ((T2)this).x);
System.out.println("((T1)this).x=\t" + ((T1)this).x);
System.out.println("((I)this).x=\t" + ((I)this).x);
}
}
class Test {
public static void main(String[] args) {
new T3().test();
}
}
This program produces the output:
x= 3
super.x= 2
((T2)this).x= 2
((T1)this).x= 1
((I)this).x= 0
Within class T3
, the expression super.x
has
the same effect as ((T2)this).x
when x
has
package access. Note that super.x
is not specified in terms
of a cast, due to difficulties around access to protected
members of the superclass.
15.12 Method Invocation Expressions
15.12.3 Compile-Time Step 3: Is the Chosen Method Appropriate?
If there is a most specific method declaration for a method invocation, it is called the compile-time declaration for the method invocation.
It is a compile-time error if an argument to a method invocation is not compatible with its target type, as derived from the invocation type of the compile-time declaration.
If the compile-time declaration is applicable by variable arity
invocation, then where the last formal parameter type of the invocation
type of the method is Fn[]
, it is a
compile-time error if the type which is the erasure of
Fn is not accessible (6.6)
at the point of invocation.
If the compile-time declaration is void
, then the method
invocation must be a top level expression (that is, the
Expression in an expression statement or in the
ForInit or ForUpdate part of a for
statement), or a compile-time error occurs. Such a method invocation
produces no value and so must be used only in a situation where a value
is not needed.
In addition, whether the compile-time declaration is appropriate may depend on the form of the method invocation expression before the left parenthesis, as follows:
If the form is MethodName - that is, just an Identifier - and the compile-time declaration is an instance method, then:
It is a compile-time error if the method invocation occurs in a static context (8.1.3) or in a pre-initialization context of the associated instance (8.8.7.1).
Otherwise, let T be the class or interface to search (15.12.1). It is a compile-time error if the innermost enclosing class or interface declaration of the method invocation is neither T nor an inner class of T.
If the form is TypeName
.
[TypeArguments] Identifier, then the compile-time declaration must bestatic
, or a compile-time error occurs.If the form is ExpressionName
.
[TypeArguments] Identifier or Primary.
[TypeArguments] Identifier, then the compile-time declaration must not be astatic
method declared in an interface, or a compile-time error occurs.If the form is
super
.
[TypeArguments] Identifier, then:It is a compile-time error if the compile-time declaration is
abstract
.It is a compile-time error if the method invocation occurs in a static context or in a pre-initialization context of the associated instance (8.8.7.1).
If the form is TypeName
.
super
.
[TypeArguments] Identifier, then:It is a compile-time error if the compile-time declaration is
abstract
.It is a compile-time error if the method invocation occurs in a static context or in a pre-initialization context of the associated instance.
If TypeName denotes a class C, then if the class or interface declaration immediately enclosing the method invocation is not C or an inner class of C, a compile-time error occurs.
If TypeName denotes an interface, let E be the class or interface declaration immediately enclosing the method invocation. A compile-time error occurs if there exists a method, distinct from the compile-time declaration, that overrides (9.4.1) the compile-time declaration from a direct superclass or direct superinterface of E.
In the case that a superinterface overrides a method declared in a grandparent interface, this rule prevents the child interface from "skipping" the override by simply adding the grandparent to its list of direct superinterfaces. The appropriate way to access functionality of a grandparent is through the direct superinterface, and only if that interface chooses to expose the desired behavior. (Alternately, the programmer is free to define an additional superinterface that exposes the desired behavior with a
super
method invocation.)
The compile-time parameter types and compile-time result are determined as follows:
If the compile-time declaration for the method invocation is not a signature polymorphic method, then:
The compile-time parameter types are the types of the formal parameters of the compile-time declaration.
The compile-time result is the result of the invocation type of the compile-time declaration (15.12.2.6).
If the compile-time declaration for the method invocation is a signature polymorphic method, then:
The compile-time parameter types are the types of the actual argument expressions. An argument expression which is the null literal
null
(3.10.8) is treated as having the typeVoid
.The compile-time result is determined as follows:
If the signature polymorphic method is either
void
or has a return type other thanObject
, the compile-time result is the result of the invocation type of the compile-time declaration (15.12.2.6).Otherwise, if the method invocation expression is an expression statement, the compile-time result is
void
.Otherwise, if the method invocation expression is the operand of a cast expression (15.16), the compile-time result is the erasure of the type of the cast expression (4.6).
Otherwise, the compile-time result is the signature polymorphic method's return type,
Object
.
A method is signature polymorphic if all of the following are true:
It is declared in the
java.lang.invoke.MethodHandle
class or thejava.lang.invoke.VarHandle
class.It has a single variable arity parameter (8.4.1) whose declared type is
Object[]
.It is
native
.
The following compile-time information is then associated with the method invocation for use at run time:
The name of the method.
The qualifying class or interface of the method invocation (13.1).
The number of parameters and the compile-time parameter types, in order.
The compile-time result.
The invocation mode, computed as follows:
If the compile-time declaration has the
static
modifier, then the invocation mode isstatic
.Otherwise, if the part of the method invocation before the left parenthesis is of the form
super
.
Identifier or of the form TypeName.
super
.
Identifier, then the invocation mode issuper
.Otherwise, if the qualifying class or interface of the method invocation is in fact an interface, then the invocation mode is
interface
.Otherwise, the invocation mode is
virtual
.
If the result of the invocation type of the compile-time declaration
is not void
, then the type of the method invocation
expression is obtained by applying capture conversion (5.1.10)
to the return type of the invocation type of the compile-time
declaration.
15.13 Method Reference Expressions
A method reference expression is used to refer to the invocation of a method without actually performing the invocation. Certain forms of method reference expression also allow class instance creation (15.9) or array creation (15.10) to be treated as if it were a method invocation.
- MethodReference:
-
ExpressionName
::
[TypeArguments] Identifier -
Primary
::
[TypeArguments] Identifier -
ReferenceType
::
[TypeArguments] Identifier -
super
::
[TypeArguments] Identifier -
TypeName
.
super
::
[TypeArguments] Identifier -
ClassType
::
[TypeArguments]new
-
ArrayType
::
new
If TypeArguments is present to the right of ::
,
then it is a compile-time error if any of the type arguments are
wildcards (4.5.1).
If a method reference expression has the form ExpressionName
::
[TypeArguments] Identifier or
Primary ::
[TypeArguments]
Identifier, it is a compile-time error if the type of the
ExpressionName or Primary is not a reference type.
If a method reference expression has the form super
::
[TypeArguments] Identifier, let
E be the class or interface declaration immediately enclosing
the method reference expression. It is a compile-time error if
E is the class Object
or if E is an
interface.
If a method reference expression has the form TypeName
.
super
::
[TypeArguments] Identifier, then:
If TypeName denotes a class, C, then it is a compile-time error if C is not a lexically enclosing class of the current class, or if C is the class
Object
.If TypeName denotes an interface, I, then let E be the class or interface declaration immediately enclosing the method reference expression. It is a compile-time error if I is not a direct superinterface of E, or if there exists some other direct superclass or direct superinterface of E, J, such that J is a subclass or subinterface of I.
If TypeName denotes a type variable, then a compile-time error occurs.
If a method reference expression has the form super
::
[TypeArguments] Identifier or
TypeName .
super
::
[TypeArguments] Identifier, it is a compile-time error
if the expression occurs in a static context (8.1.3) or in a pre-initialization context
of the associated instance (8.8.7.1).
If a method reference expression has the form ClassType
::
[TypeArguments] new
, then:
ClassType must name a class that is accessible (6.6), non-
abstract
, and not an enum class, or a compile-time error occurs.If ClassType denotes a parameterized type (4.5), then it is a compile-time error if any of its type arguments are wildcards.
If ClassType denotes a raw type (4.8), then it is a compile-time error if TypeArguments is present after the
::
.
If a method reference expression has the form ArrayType
::
new
, then ArrayType must denote a
type that is reifiable (4.7),
or a compile-time error occurs.
The target reference of an instance method (15.12.4.1)
may be provided by the method reference expression using an
ExpressionName, a Primary, or super
, or
it may be provided later when the method is invoked. The immediately
enclosing instance of a new inner class instance (15.9.2)
is provided by a lexically enclosing instance of this
(8.1.3).
When more than one member method of a type has the same name, or when a class has more than one constructor, the appropriate method or constructor is selected based on the functional interface type targeted by the method reference expression, as specified in 15.13.1.
If a method or constructor is generic, the appropriate type arguments may either be inferred or provided explicitly. Similarly, the type arguments of a generic type mentioned by the method reference expression may be provided explicitly or inferred.
Method reference expressions are always poly expressions (15.2).
It is a compile-time error if a method reference expression occurs in a program in someplace other than an assignment context (5.2), an invocation context (5.3), or a casting context (5.5).
Evaluation of a method reference expression produces an instance of a functional interface type (9.8). This does not cause the execution of the corresponding method; instead, the execution may occur at a later time when an appropriate method of the functional interface is invoked.
Here are some method reference expressions, first with no target reference and then with a target reference:
String::length // instance method System::currentTimeMillis // static method List<String>::size // explicit type arguments for generic type List::size // inferred type arguments for generic type int[]::clone T::tvarMember System.out::println "abc"::length foo[x]::bar (test ? list.replaceAll(String::trim) : list) :: iterator super::toString
Here are some more method reference expressions:
String::valueOf // overload resolution needed Arrays::sort // type arguments inferred from context Arrays::<String>sort // explicit type arguments
Here are some method reference expressions that represent a deferred creation of an object or an array:
ArrayList<String>::new // constructor for parameterized type ArrayList::new // inferred type arguments // for generic class Foo::<Integer>new // explicit type arguments // for generic constructor Bar<String>::<Integer>new // generic class, generic constructor Outer.Inner::new // inner class constructor int[]::new // array creation
It is not possible to specify a particular signature to be matched, for example,
Arrays::sort(int[])
. Instead, the functional interface provides argument types that are used as input to the overload resolution algorithm (15.12.2). This should satisfy the vast majority of use cases; when the rare need arises for more precise control, a lambda expression can be used.
The use of type argument syntax in the class name before a delimiter (
List<String>::size
) raises the parsing problem of distinguishing between<
as a type argument bracket and<
as a less-than operator. In theory, this is no worse than allowing type arguments in cast expressions; however, the difference is that the cast case only comes up when a(
token is encountered; with the addition of method reference expressions, the start of every expression is potentially a parameterized type.
15.13.1 Compile-Time Declaration of a Method Reference
The compile-time declaration of a method reference expression is the method to which the expression refers. In special cases, the compile-time declaration does not actually exist, but is a notional method that represents a class instance creation or an array creation. The choice of compile-time declaration depends on a function type targeted by the expression, just as the compile-time declaration of a method invocation depends on the invocation's arguments (15.12.3).
The search for a compile-time declaration mirrors the process for method invocations in 15.12.1 and 15.12.2, as follows:
First, a type to search is determined:
If the method reference expression has the form ExpressionName
::
[TypeArguments] Identifier or Primary::
[TypeArguments] Identifier, the type to search is the type of the expression preceding the::
token.If the method reference expression has the form ReferenceType
::
[TypeArguments] Identifier, the type to search is the result of capture conversion (5.1.10) applied to ReferenceType.If the method reference expression has the form
super
::
[TypeArguments] Identifier, the type to search is the superclass type of the immediately enclosing class or interface declaration of the method reference expression.Let T be the class or interface declaration immediately enclosing the method reference expression. It is a compile-time error if T is the class
Object
or an interface.If the method reference expression has the form TypeName
.
super
::
[TypeArguments] Identifier, then if TypeName denotes a class, the type to search is the superclass type of the named class; otherwise, TypeName denotes an interface to search.It is a compile-time error if TypeName is neither a lexically enclosing class or interface declaration of the method reference expression, nor a direct superinterface of the immediately enclosing class or interface declaration of the method reference expression.
It is a compile-time error if TypeName is the class Object.
It is a compile-time error if TypeName is an interface, and there exists some other direct superclass or direct superinterface of the immediately enclosing class or interface declaration of the method reference expression, J, such that J is a subclass or subinterface of TypeName.
For the two other forms (involving
::
new
), the referenced method is notional and there is no type to search.
Second, given a targeted function type with n parameters, a set of potentially applicable methods is identified:
If the method reference expression has the form ReferenceType
::
[TypeArguments] Identifier, then the potentially applicable methods are:the member methods of the type to search that would be potentially applicable (15.12.2.1) for a method invocation which names Identifier, has arity n, has type arguments TypeArguments, and appears in the same class as the method reference expression; plus
the member methods of the type to search that would be potentially applicable for a method invocation which names Identifier, has arity n-1, has type arguments TypeArguments, and appears in the same class as the method reference expression.
Two different arities, n and n-1, are considered, to account for the possibility that this form refers to either a
static
method or an instance method.If the method reference expression has the form ClassType
::
[TypeArguments]new
, then the potentially applicable methods are a set of notional methods corresponding to the constructors of ClassType.If ClassType is a raw type, but is not a non-
static
member type of a raw type, the candidate notional member methods are those specified in 15.9.3 for a class instance creation expression that uses<>
to elide the type arguments to a class. Otherwise, the candidate notional member methods are the constructors of ClassType, treated as if they were methods with return type ClassType.Among these candidates, the potentially applicable methods are the notional methods that would be potentially applicable for a method invocation which has arity n, has type arguments TypeArguments, and appears in the same class as the method reference expression.
If the method reference expression has the form ArrayType
::
new
, a single notional method is considered. The method has a single parameter of typeint
, returns the ArrayType, and has nothrows
clause. If n = 1, this is the only potentially applicable method; otherwise, there are no potentially applicable methods.For all other forms, the potentially applicable methods are the member methods of the type to search that would be potentially applicable for a method invocation which names Identifier, has arity n, has type argument TypeArguments, and appears in the same class as the method reference expression.
Finally, if there are no potentially applicable methods, then there is no compile-time declaration.
Otherwise, given a targeted function type with parameter types P1, ..., Pn and a set of potentially applicable methods, the compile-time declaration is selected as follows:
If the method reference expression has the form ReferenceType
::
[TypeArguments] Identifier, then two searches for a most specific applicable method are performed. Each search is as specified in 15.12.2.2 through 15.12.2.5, with the clarifications below. Each search produces a set of applicable methods and, possibly, designates a most specific method of the set. In the case of an error as specified in 15.12.2.4, the set of applicable methods is empty. In the case of an error as specified in 15.12.2.5, there is no most specific method.In the first search, the method reference is treated as if it were an invocation with argument expressions of types P1, ..., Pn. Type arguments, if any, are given by the method reference expression.
In the second search, if P1, ..., Pn is not empty and P1 is a subtype of ReferenceType, then the method reference expression is treated as if it were a method invocation expression with argument expressions of types P2, ..., Pn. If ReferenceType is a raw type, and there exists a parameterization of this type, G
<
...>
, that is a supertype of P1, the type to search is the result of capture conversion (5.1.10) applied to G<
...>
; otherwise, the type to search is the same as the type of the first search. Type arguments, if any, are given by the method reference expression.If the first search produces a most specific method that is
static
, and the set of applicable methods produced by the second search contains no non-static
methods, then the compile-time declaration is the most specific method of the first search.Otherwise, if the set of applicable methods produced by the first search contains no
static
methods, and the second search produces a most specific method that is non-static
, then the compile-time declaration is the most specific method of the second search.Otherwise, there is no compile-time declaration.
For all other forms of method reference expression, one search for a most specific applicable method is performed. The search is as specified in 15.12.2.2 through 15.12.2.5, with the clarifications below.
The method reference is treated as if it were an invocation with argument expressions of types P1, ..., Pn; the type arguments, if any, are given by the method reference expression.
If the search results in an error as specified in 15.12.2.2 through 15.12.2.5, or if the most specific applicable method is
static
, there is no compile-time declaration.Otherwise, the compile-time declaration is the most specific applicable method.
It is a compile-time error if a method reference expression has the
form ReferenceType ::
[TypeArguments]
Identifier, and the compile-time declaration is
static
, and ReferenceType is not a simple or
qualified name (6.2).
It is a compile-time error if the method reference expression has the
form super
::
[TypeArguments]
Identifier or TypeName .
super
::
[TypeArguments]
Identifier, and the compile-time declaration is
abstract
.
It is a compile-time error if the method reference expression has the
form super
::
[TypeArguments]
Identifier or TypeName .
super
::
[TypeArguments]
Identifier, and the method reference expression occurs in a
static context (8.1.3) or in a
pre-initialization context of the associated instance (8.8.7.1).
It is a compile-time error if the method reference expression has the
form TypeName .
super
::
[TypeArguments] Identifier, and TypeName
denotes a class C, and the immediately enclosing class or
interface declaration of the method reference expression is not
C or an inner class of C.
It is a compile-time error if the method reference expression has the
form TypeName .
super
::
[TypeArguments] Identifier, and TypeName
denotes an interface, and there exists a method, distinct from the
compile-time declaration, that overrides the compile-time declaration
from a direct superclass or direct superinterface of the class or
interface whose declaration immediately encloses the method reference
expression (8.4.8,
9.4.1).
It is a compile-time error if the method reference expression is of
the form ClassType ::
[TypeArguments]
new
and a compile-time error would occur when determining
an enclosing instance for ClassType as specified in 15.9.2
(treating the method reference expression as if it were an unqualified
class instance creation expression).
A method reference expression of the form ReferenceType
::
[TypeArguments] Identifier can be interpreted in different ways. If Identifier refers to an instance method, then the implicit lambda expression has an extra parameter compared to if Identifier refers to astatic
method. It is possible for ReferenceType to have both kinds of applicable methods, so the search algorithm described above identifies them separately, since there are different parameter types for each case.
An example of ambiguity is:
interface Fun<T,R> { R apply(T arg); } class C { int size() { return 0; } static int size(Object arg) { return 0; } void test() { Fun<C, Integer> f1 = C::size; // Error: instance method size() // or static method size(Object)? } }
This ambiguity cannot be resolved by providing an applicable instance method which is more specific than an applicable
static
method:
interface Fun<T,R> { R apply(T arg); } class C { int size() { return 0; } static int size(Object arg) { return 0; } int size(C arg) { return 0; } void test() { Fun<C, Integer> f1 = C::size; // Error: instance method size() // or static method size(Object)? } }
The search is smart enough to ignore ambiguities in which all the applicable methods (from both searches) are instance methods:
interface Fun<T,R> { R apply(T arg); } class C { int size() { return 0; } int size(Object arg) { return 0; } int size(C arg) { return 0; } void test() { Fun<C, Integer> f1 = C::size; // OK: reference is to instance method size() } }
For convenience, when the name of a generic type is used to refer to an instance method (where the receiver becomes the first parameter), the target type is used to determine the type arguments. This facilitates usage like
Pair::first
in place ofPair<String,Integer>::first
. Similarly, a method reference likePair::new
is treated like a "diamond" instance creation (new Pair<>()
). Because the "diamond" is implicit, this form does not instantiate a raw type; in fact, there is no way to express a reference to the constructor of a raw type.
For some method reference expressions, there is only one possible compile-time declaration with only one possible invocation type (15.12.2.6), regardless of the targeted function type. Such method reference expressions are said to be exact. A method reference expression that is not exact is said to be inexact.
A method reference expression ending with Identifier is exact if it satisfies all of the following:
If the method reference expression has the form ReferenceType
::
[TypeArguments] Identifier, then ReferenceType does not denote a raw type.The type to search has exactly one member method with the name Identifier that is accessible to the class or interface in which the method reference expression appears.
This method is not variable arity (8.4.1).
If this method is generic (8.4.4), then the method reference expression provides TypeArguments.
A method reference expression of the form ClassType
::
[TypeArguments] new
is exact if it
satisfies all of the following:
The type denoted by ClassType is not raw, or is a non-
static
member type of a raw type.The type denoted by ClassType has exactly one constructor that is accessible to the class or interface in which the method reference expression appears.
This constructor is not variable arity.
If this constructor is generic, then the method reference expression provides TypeArguments.
A method reference expression of the form ArrayType
::
new
is always exact.