This document describes changes to the Java Language Specification to support pattern matching in instanceof
expressions. See JEP 305.
Changes are described with respect to existing sections of the JLS. New text is indicated like this and deleted text is indicated like this. Explanation and discussion, as needed, is set aside in grey boxes.
Chapter 1: Introduction
1.1 Organization of the Specification
Chapter 2 describes grammars and the notation used to present the lexical and syntactic grammars for the language.
Chapter 3 describes the lexical structure of the Java programming language, which is based on C and C++. The language is written in the Unicode character set. It supports the writing of Unicode characters on systems that support only ASCII.
Chapter 4 describes types, values, and variables. Types are subdivided into primitive types and reference types.
The primitive types are defined to be the same on all machines and in all implementations, and are various sizes of two's-complement integers, single- and double-precision IEEE 754 standard floating-point numbers, a boolean
type, and a Unicode character char
type. Values of the primitive types do not share state.
Reference types are the class types, the interface types, and the array types. The reference types are implemented by dynamically created objects that are either instances of classes or arrays. Many references to each object can exist. All objects (including arrays) support the methods of the class Object
, which is the (single) root of the class hierarchy. A predefined String
class supports Unicode character strings. Classes exist for wrapping primitive values inside of objects. In many cases, wrapping and unwrapping is performed automatically by the compiler (in which case, wrapping is called boxing, and unwrapping is called unboxing). Class and interface declarations may be generic, that is, they may be parameterized by other reference types. Such declarations may then be invoked with specific type arguments.
Variables are typed storage locations. A variable of a primitive type holds a value of that exact primitive type. A variable of a class type can hold a null reference or a reference to an object whose type is that class type or any subclass of that class type. A variable of an interface type can hold a null reference or a reference to an instance of any class that implements the interface. A variable of an array type can hold a null reference or a reference to an array. A variable of class type Object
can hold a null reference or a reference to any object, whether class instance or array.
Chapter 5 describes conversions and numeric promotions. Conversions change the compile-time type and, sometimes, the value of an expression. These conversions include the boxing and unboxing conversions between primitive types and reference types. Numeric promotions are used to convert the operands of a numeric operator to a common type where an operation can be performed. There are no loopholes in the language; casts on reference types are checked at run time to ensure type safety.
Chapter 6 describes declarations and names, and how to determine what names mean (that is, which declaration a name denotes). The Java programming language does not require classes and interfaces, or their members, to be declared before they are used. Declaration order is significant only for local variables, local classes, and the order of field initializers in a class or interface. Recommended naming conventions that make for more readable programs are described here.
Chapter 7 describes the structure of a program, which is organized into packages. The members of a package are classes, interfaces, and subpackages. Packages, and consequently their members, have names in a hierarchical name space; the Internet domain name system can usually be used to form unique package names. Compilation units contain declarations of the classes and interfaces that are members of a given package, and may import classes and interfaces from other packages to give them short names.
Packages may be grouped into modules that serve as building blocks in the construction of very large programs. The declaration of a module specifies which other modules (and thus packages, and thus classes and interfaces) are required in order to compile and run code in its own packages.
The Java programming language supports limitations on external access to the members of packages, classes, and interfaces. The members of a package may be accessible solely by other members in the same package, or by members in other packages of the same module, or by members of packages in different modules. Similar constraints apply to the members of classes and interfaces.
Chapter 8 describes classes. The members of classes are classes, interfaces, fields (variables) and methods. Class variables exist once per class. Class methods operate without reference to a specific object. Instance variables are dynamically created in objects that are instances of classes. Instance methods are invoked on instances of classes; such instances become the current object this
during their execution, supporting the object-oriented programming style.
Classes support single inheritance, in which each class has a single superclass. Each class inherits members from its superclass, and ultimately from the class Object
. Variables of a class type can reference an instance of that class or of any subclass of that class, allowing new types to be used with existing methods, polymorphically.
Classes support concurrent programming with synchronized
methods. Methods declare the checked exceptions that can arise from their execution, which allows compile-time checking to ensure that exceptional conditions are handled. Objects can declare a finalize
method that will be invoked before the objects are discarded by the garbage collector, allowing the objects to clean up their state.
For simplicity, the language has neither declaration "headers" separate from the implementation of a class nor separate type and class hierarchies.
A special form of classes, enums, support the definition of small sets of values and their manipulation in a type safe manner. Unlike enumerations in other languages, enums are objects and may have their own methods.
Chapter 9 describes interfaces. The members of interfaces are classes, interfaces, constant fields, and methods. Classes that are otherwise unrelated can implement the same interface. A variable of an interface type can contain a reference to any object that implements the interface.
Classes and interfaces support multiple inheritance from interfaces. A class that implements one or more interfaces may inherit instance methods from both its superclass and its superinterfaces.
Annotation types are specialized interfaces used to annotate declarations. Such annotations are not permitted to affect the semantics of programs in the Java programming language in any way. However, they provide useful input to various tools.
Chapter 10 describes arrays. Array accesses include bounds checking. Arrays are dynamically created objects and may be assigned to variables of type Object
. The language supports arrays of arrays, rather than multidimensional arrays.
Chapter 11 describes exceptions, which are nonresuming and fully integrated with the language semantics and concurrency mechanisms. There are three kinds of exceptions: checked exceptions, run-time exceptions, and errors. The compiler ensures that checked exceptions are properly handled by requiring that a method or constructor can result in a checked exception only if the method or constructor declares it. This provides compile-time checking that exception handlers exist, and aids programming in the large. Most user-defined exceptions should be checked exceptions. Invalid operations in the program detected by the Java Virtual Machine result in run-time exceptions, such as NullPointerException
. Errors result from failures detected by the Java Virtual Machine, such as OutOfMemoryError
. Most simple programs do not try to handle errors.
Chapter 12 describes activities that occur during execution of a program. A program is normally stored as binary files representing compiled classes and interfaces. These binary files can be loaded into a Java Virtual Machine, linked to other classes and interfaces, and initialized.
After initialization, class methods and class variables may be used. Some classes may be instantiated to create new objects of the class type. Objects that are class instances also contain an instance of each superclass of the class, and object creation involves recursive creation of these superclass instances.
When an object is no longer referenced, it may be reclaimed by the garbage collector. If an object declares a finalizer, the finalizer is executed before the object is reclaimed to give the object a last chance to clean up resources that would not otherwise be released. When a class is no longer needed, it may be unloaded.
Chapter 13 describes binary compatibility, specifying the impact of changes to types on other types that use the changed types but have not been recompiled. These considerations are of interest to developers of types that are to be widely distributed, in a continuing series of versions, often through the Internet. Good program development environments automatically recompile dependent code whenever a type is changed, so most programmers need not be concerned about these details.
Chapter 14 describes blocks and statements, which are based on C and C++, and patterns, which provide a means for describing the shape of data. The language has no goto
statement, but includes labeled break
and continue
statements. Unlike C, the Java programming language requires boolean
(or Boolean
) expressions in control-flow statements, and does not convert types to boolean
implicitly (except through unboxing), in the hope of catching more errors at compile time. A synchronized
statement provides basic object-level monitor locking. A try
statement can include catch
and finally
clauses to protect against non-local control transfers.
Chapter 15 describes expressions. This document fully specifies the (apparent) order of evaluation of expressions, for increased determinism and portability. Overloaded methods and constructors are resolved at compile time by picking the most specific method or constructor from those which are applicable.
Chapter 16 describes the precise way in which the language ensures that local variables are definitely set before use. While all other variables are automatically initialized to a default value, the Java programming language does not automatically initialize local variables in order to avoid masking programming errors.
Chapter 17 describes the semantics of threads and locks, which are based on the monitor-based concurrency originally introduced with the Mesa programming language. The Java programming language specifies a memory model for shared-memory multiprocessors that supports high-performance implementations.
Chapter 18 describes a variety of type inference algorithms used to test applicability of generic methods and to infer types in a generic method invocation.
Chapter 19 presents a syntactic grammar for the language.
Chapter 4: Types, Values, and Variables
4.11 Where Types Are Used
Types are used in most kinds of declaration and in certain kinds of expression. Specifically, there are 16 17 type contexts where types are used:
In declarations:
A type in the
extends
orimplements
clause of a class declaration (8.1.4, 8.1.5, 8.5, 9.5)A type in the
extends
clause of an interface declaration (9.1.3, 8.5, 9.5)The return type of a method (including the type of an element of an annotation type) (8.4.5, 9.4, 9.6.1)
A type in the
throws
clause of a method or constructor (8.4.6, 8.8.5, 9.4)A type in the
extends
clause of a type parameter declaration of a generic class, interface, method, or constructor (8.1.2, 9.1.2, 8.4.4, 8.8.4)The type in a field declaration of a class or interface (including an enum constant) (8.3, 9.3, 8.9.1)
The type in a formal parameter declaration of a method, constructor, or lambda expression (8.4.1, 8.8.1, 9.4, 15.27.1)
The type of the receiver parameter of a method (8.4)
The type in a local variable declaration (14.4, 14.14.1, 14.14.2, 14.20.3)
The type in an exception parameter declaration (14.20)
- The type in the declaration of a pattern variable (14.30.1)
In expressions:
A type in the explicit type argument list to an explicit constructor invocation statement or class instance creation expression or method invocation expression (8.8.7.1, 15.9, 15.12)
In an unqualified class instance creation expression, as the class type to be instantiated (15.9) or as the direct superclass or direct superinterface of an anonymous class to be instantiated (15.9.5)
The element type in an array creation expression (15.10.1)
The type in the cast operator of a cast expression (15.16)
The type that follows the type
instanceof
relational operator (15.20.2)In a method reference expression (15.13), as the reference type to search for a member method or as the class type or array type to construct.
Also, types are used as:
The element type of an array type in any of the above contexts; and
A non-wildcard type argument, or a bound of a wildcard type argument, of a parameterized type in any of the above contexts.
Finally, there are three special terms in the Java programming language which denote the use of a type:
An unbounded wildcard (4.5.1)
The
...
in the type of a variable arity parameter (8.4.1), to indicate an array typeThe simple name of a type in a constructor declaration (8.8), to indicate the class of the constructed object
The meaning of types in type contexts is given by:
4.2, for primitive types
4.4, for type parameters
4.5, for class and interface types that are parameterized, or appear either as type arguments in a parameterized type or as bounds of wildcard type arguments in a parameterized type
4.8, for class and interface types that are raw
4.9, for intersection types in the bounds of type parameters
6.5, for class and interface types in contexts where genericity is unimportant (6.1)
10.1, for array types
Some type contexts restrict how a reference type may be parameterized:
The following type contexts require that if a type is a parameterized reference type, it has no wildcard type arguments:
In an
extends
orimplements
clause of a class declaration (8.1.4, 8.1.5)In an
extends
clause of an interface declaration (9.1.3)In an unqualified class instance creation expression, as the class type to be instantiated (15.9) or as the direct superclass or direct superinterface of an anonymous class to be instantiated (15.9.5)
In a method reference expression (15.13), as the reference type to search for a member method or as the class type or array type to construct.
In addition, no wildcard type arguments are permitted in the explicit type argument list to an explicit constructor invocation statement or class instance creation expression or method invocation expression or method reference expression (8.8.7.1, 15.9, 15.12, 15.13).
The following type contexts require that if a type is a parameterized reference type, it has only unbounded wildcard type arguments (i.e. it is a reifiable type) :
The following type contexts disallow a parameterized reference type altogether, because they involve exceptions and the type of an exception is non-generic (6.1):
In any type context where a type is used, it is possible to annotate the keyword denoting a primitive type or the Identifier denoting the simple name of a reference type. It is also possible to annotate an array type by writing an annotation to the left of the
[
at the desired level of nesting in the array type. Annotations in these locations are called type annotations, and are specified in 9.7.4. Here are some examples:
@Foo int[] f;
annotates the primitive typeint
int @Foo [] f;
annotates the array typeint[]
int @Foo [][] f;
annotates the array typeint[][]
int[] @Foo [] f;
annotates the array typeint[]
which is the component type of the array typeint[][]
Five of the type contexts which appear in declarations occupy the same syntactic real estate as a number of declaration contexts (9.6.4.1):
The return type of a method (including the type of an element of an annotation type)
The type in a field declaration of a class or interface (including an enum constant)
The type in a formal parameter declaration of a method, constructor, or lambda expression
The type in a local variable declaration
The type in an exception parameter declaration
The fact that the same syntactic location in a program can be both a type context and a declaration context arises because the modifiers for a declaration immediately precede the type of the declared entity. 9.7.4 explains how an annotation in such a location is deemed to appear in a type context or a declaration context or both.
Example 4.11-1. Usage of a Type
import java.util.Random;
import java.util.Collection;
import java.util.ArrayList;
class MiscMath<T extends Number> {
int divisor;
MiscMath(int divisor) { this.divisor = divisor; }
float ratio(long l) {
try {
l /= divisor;
} catch (Exception e) {
if (e instanceof ArithmeticException)
l = Long.MAX_VALUE;
else
l = 0;
}
return (float)l;
}
double gausser() {
Random r = new Random();
double[] val = new double[2];
val[0] = r.nextGaussian();
val[1] = r.nextGaussian();
return (val[0] + val[1]) / 2;
}
Collection<Number> fromArray(Number[] na) {
Collection<Number> cn = new ArrayList<Number>();
for (Number n : na) cn.add(n);
return cn;
}
<S> void loop(S s) { this.<S>loop(s); }
}
In this example, types are used in declarations of the following:
Imported types (7.5); here the type
Random
, imported from the typejava.util.Random
of the packagejava.util
, is declaredFields, which are the class variables and instance variables of classes (8.3), and constants of interfaces (9.3); here the field
divisor
in the classMiscMath
is declared to be of typeint
Method parameters (8.4.1); here the parameter
l
of the methodratio
is declared to be of typelong
Method results (8.4); here the result of the method
ratio
is declared to be of typefloat
, and the result of the methodgausser
is declared to be of typedouble
Constructor parameters (8.8.1); here the parameter of the constructor for
MiscMath
is declared to be of typeint
Local variables (14.4, 14.14); the local variables
r
andval
of the methodgausser
are declared to be of typesRandom
anddouble[]
(array ofdouble
)Exception parameters (14.20); here the exception parameter
e
of thecatch
clause is declared to be of typeException
Type parameters (4.4); here the type parameter of
MiscMath
is a type variableT
with the typeNumber
as its declared boundIn any declaration that uses a parameterized type; here the type
Number
is used as a type argument (4.5.1) in the parameterized typeCollection<Number>
.
and in expressions of the following kinds:
Class instance creations (15.9); here a local variable
r
of methodgausser
is initialized by a class instance creation expression that uses the typeRandom
Generic class (8.1.2) instance creations (15.9); here
Number
is used as a type argument in the expressionnew ArrayList<Number>()
Array creations (15.10.1); here the local variable
val
of methodgausser
is initialized by an array creation expression that creates an array ofdouble
with size 2Generic method (8.4.4) or constructor (8.8.4) invocations (15.12); here the method
loop
calls itself with an explicit type argumentS
Casts (15.16); here the
return
statement of the methodratio
uses thefloat
type in a castThe
instanceof
operator (15.20.2); here theinstanceof
operator tests whethere
is assignment-compatible with the typeArithmeticException
4.12 Variables
4.12.3 Kinds of Variables
There are eight nine kinds of variables:
A class variable is a field declared using the keyword
static
within a class declaration (8.3.1.1), or with or without the keywordstatic
within an interface declaration (9.3).A class variable is created when its class or interface is prepared (12.3.2) and is initialized to a default value (4.12.5). The class variable effectively ceases to exist when its class or interface is unloaded (12.7).
An instance variable is a field declared within a class declaration without using the keyword
static
(8.3.1.1).If a class T has a field
a
that is an instance variable, then a new instance variablea
is created and initialized to a default value (4.12.5) as part of each newly created object of class T or of any class that is a subclass of T (8.1.4). The instance variable effectively ceases to exist when the object of which it is a field is no longer referenced, after any necessary finalization of the object (12.6) has been completed.Array components are unnamed variables that are created and initialized to default values (4.12.5) whenever a new object that is an array is created (10, 15.10.2). The array components effectively cease to exist when the array is no longer referenced.
Method parameters (8.4.1) name argument values passed to a method.
For every parameter declared in a method declaration, a new parameter variable is created each time that method is invoked (15.12). The new variable is initialized with the corresponding argument value from the method invocation. The method parameter effectively ceases to exist when the execution of the body of the method is complete.
Constructor parameters (8.8.1) name argument values passed to a constructor.
For every parameter declared in a constructor declaration, a new parameter variable is created each time a class instance creation expression (15.9) or explicit constructor invocation (8.8.7) invokes that constructor. The new variable is initialized with the corresponding argument value from the creation expression or constructor invocation. The constructor parameter effectively ceases to exist when the execution of the body of the constructor is complete.
Lambda parameters (15.27.1) name argument values passed to a lambda expression body (15.27.2).
For every parameter declared in a lambda expression, a new parameter variable is created each time a method implemented by the lambda body is invoked (15.12). The new variable is initialized with the corresponding argument value from the method invocation. The lambda parameter effectively ceases to exist when the execution of the lambda expression body is complete.
An exception parameter is created each time an exception is caught by a
catch
clause of atry
statement (14.20).The new variable is initialized with the actual object associated with the exception (11.3, 14.18). The exception parameter effectively ceases to exist when execution of the block associated with the
catch
clause is complete.Local variables are declared by local variable declaration statements (14.4).
Whenever the flow of control enters a block (14.2) or
for
statement (14.14), a new variable is created for each local variable declared in a local variable declaration statement immediately contained within that block orfor
statement.A local variable declaration statement may contain an expression which initializes the variable. The local variable with an initializing expression is not initialized, however, until the local variable declaration statement that declares it is executed. (The rules of definite assignment (16) prevent the value of a local variable from being used before it has been initialized or otherwise assigned a value.) The local variable effectively ceases to exist when the execution of the block or for statement is complete.
Were it not for one exceptional situation, a local variable could always be regarded as being created when its local variable declaration statement is executed. The exceptional situation involves the
switch
statement (14.11), where it is possible for control to enter a block but bypass execution of a local variable declaration statement. Because of the restrictions imposed by the rules of definite assignment (16), however, the local variable declared by such a bypassed local variable declaration statement cannot be used before it has been definitely assigned a value by an assignment expression (15.26).
- Pattern variables are declared in patterns. Pattern variables are assigned a value by the process of pattern matching (14.30.3). This process is conditional; a pattern variable is only assigned a value if the pattern match succeeds. For this reason, pattern variables require special rules restricting their use (6.3).
Example 4.12.3-1. Different Kinds of Variables
This example has been updated to include pattern variables.
class Point {
static int numPoints; // numPoints is a class variable
int x, y; // x and y are instance variables
int[] w = new int[10]; // w[0] is an array component
int setX(int x) { // x is a method parameter
int oldx = this.x; // oldx is a local variable
this.x = x;
return oldx;
}
boolean equalAtX(Object o) {
if (o instanceof Point p) // p is a pattern variable
return this.x == p.x;
else
return false;
}
}
4.12.4 final
Variables
A variable can be declared final
. A final
variable may only be assigned to once. It is a compile-time error if a final
variable is assigned to unless it is definitely unassigned immediately prior to the assignment (16).
Once a final
variable has been assigned, it always contains the same value. If a final
variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object. This applies also to arrays, because arrays are objects; if a final
variable holds a reference to an array, then the components of the array may be changed by operations on the array, but the variable will always refer to the same array.
A blank final
is a final
variable whose declaration lacks an initializer.
A constant variable is a final
variable of primitive type or type String
that is initialized with a constant expression (15.28). Whether a variable is a constant variable or not may have implications with respect to class initialization (12.4.1), binary compatibility (13.1), reachability (14.21), and definite assignment (16.1.1).
Three Four kinds of variable are implicitly declared final
: a field of an interface (9.3), a local variable declared as a resource of a try
-with-resources statement (14.20.3), and an exception parameter of a multi-catch
clause (14.20), and a pattern variable (14.30.1). An exception parameter of a uni-catch
clause is never implicitly declared final
, but may be effectively final.
Example 4.12.4-1. Final Variables
Declaring a variable final
can serve as useful documentation that its value will not change and can help avoid programming errors. In this program:
class Point {
int x, y;
int useCount;
Point(int x, int y) { this.x = x; this.y = y; }
static final Point origin = new Point(0, 0);
}
the class Point
declares a final
class variable origin
. The origin
variable holds a reference to an object that is an instance of class Point
whose coordinates are (0, 0). The value of the variable Point.origin
can never change, so it always refers to the same Point
object, the one created by its initializer. However, an operation on this Point
object might change its state - for example, modifying its useCount
or even, misleadingly, its x
or y
coordinate.
Certain variables that are not declared final
are instead considered effectively final:
A local variable whose declarator has an initializer (14.4.2) is effectively final if all of the following are true:
It is not declared
final
.It never occurs as the left hand side in an assignment expression (15.26). (Note that the local variable declarator containing the initializer is not an assignment expression.)
It never occurs as the operand of a prefix or postfix increment or decrement operator (15.14, 15.15).
A local variable whose declarator lacks an initializer is effectively final if all of the following are true:
It is not declared
final
.Whenever it occurs as the left hand side in an assignment expression, it is definitely unassigned and not definitely assigned before the assignment; that is, it is definitely unassigned and not definitely assigned after the right hand side of the assignment expression (16).
It never occurs as the operand of a prefix or postfix increment or decrement operator.
A method, constructor, lambda, or exception parameter (8.4.1, 8.8.1, 9.4, 15.27.1, 14.20) is treated, for the purpose of determining whether it is effectively final, as a local variable whose declarator has an initializer.
If a variable is effectively final, adding the final
modifier to its declaration will not introduce any compile-time errors. Conversely, a local variable or parameter that is declared final
in a valid program becomes effectively final if the final
modifier is removed.
4.12.5 Initial Values of Variables
Every variable in a program must have a value before its value is used:
Each class variable, instance variable, or array component is initialized with a default value when it is created (15.9, 15.10.2):
For type
byte
, the default value is zero, that is, the value of(byte)0
.For type
short
, the default value is zero, that is, the value of(short)0
.For type
int
, the default value is zero, that is,0
.For type
long
, the default value is zero, that is,0L
.For type
float
, the default value is positive zero, that is,0.0f
.For type
double
, the default value is positive zero, that is,0.0d
.For type
char
, the default value is the null character, that is,'\u0000'
.For type
boolean
, the default value isfalse
.For all reference types (4.3), the default value is
null
.
Each method parameter (8.4.1) is initialized to the corresponding argument value provided by the invoker of the method (15.12).
Each constructor parameter (8.8.1) is initialized to the corresponding argument value provided by a class instance creation expression (15.9) or explicit constructor invocation (8.8.7).
Each pattern variable (14.30.1) is assigned a value after the pattern matching process has succeeded (14.30.3).
An exception parameter (14.20) is initialized to the thrown object representing the exception (11.3, 14.18).
A local variable (14.4, 14.14) must be explicitly given a value before it is used, by either initialization (14.4) or assignment (15.26), in a way that can be verified using the rules for definite assignment (16).
Example 4.12.5-1. Initial Values of Variables
class Point {
static int npoints;
int x, y;
Point root;
}
class Test {
public static void main(String[] args) {
System.out.println("npoints=" + Point.npoints);
Point p = new Point();
System.out.println("p.x=" + p.x + ", p.y=" + p.y);
System.out.println("p.root=" + p.root);
}
}
This program prints:
npoints=0
p.x=0, p.y=0
p.root=null
illustrating the default initialization of npoints
, which occurs when the class Point
is prepared (12.3.2), and the default initialization of x
, y
, and root
, which occurs when a new Point
is instantiated. See 12 for a full description of all aspects of loading, linking, and initialization of classes and interfaces, plus a description of the instantiation of classes to make new class instances.
Chapter 5: Conversions and Contexts
5.5 Casting Contexts
Casting contexts allow the operand of a cast expression (15.16) to be converted to the type explicitly named by the cast operator, and the first operand of the instanceof
operator (15.20.2) to be converted to the type indicated by the second operand. Compared to assignment contexts and invocation contexts, casting contexts allow the use of more of the conversions defined in 5.1, and allow more combinations of those conversions.
If the expression is of a primitive type, then a casting context allows the use of one of the following:
an identity conversion (5.1.1)
a widening primitive conversion (5.1.2)
a narrowing primitive conversion (5.1.3)
a widening and narrowing primitive conversion (5.1.4)
a boxing conversion (5.1.7)
a boxing conversion followed by a widening reference conversion (5.1.5)
If the expression is of a reference type, then a casting context allows the use of one of the following:
an identity conversion (5.1.1)
a widening reference conversion (5.1.5)
a widening reference conversion followed by an unboxing conversion
a widening reference conversion followed by an unboxing conversion, then followed by a widening primitive conversion
a narrowing reference conversion (5.1.6)
a narrowing reference conversion followed by an unboxing conversion
an unboxing conversion (5.1.8)
an unboxing conversion followed by a widening primitive conversion
If the expression has the null type, then the expression may be cast to any reference type.
If a casting context makes use of a narrowing reference conversion that is checked or partially unchecked (5.1.6.2, 5.1.6.3), then a run time check will be performed on the class of the expression's value, possibly causing a ClassCastException
. Otherwise, no run time check is performed.
Value set conversion (5.1.13) is applied after the type conversion.
The following tables enumerate which conversions are used in certain casting contexts. Each conversion is signified by a symbol:
- signifies no conversion allowed
≈ signifies identity conversion (5.1.1)
ω signifies widening primitive conversion (5.1.2)
η signifies narrowing primitive conversion (5.1.3)
ωη signifies widening and narrowing primitive conversion (5.1.4)
⇑ signifies widening reference conversion (5.1.5)
⇓ signifies narrowing reference conversion (5.1.6)
⊕ signifies boxing conversion (5.1.7)
⊗ signifies unboxing conversion (5.1.8)
In the tables, a comma between symbols indicates that a casting context uses one conversion followed by another. The type Object
means any reference type other than the eight wrapper classes Boolean
, Byte
, Short
, Character
, Integer
, Long
, Float
, Double
.
Table 5.5-A. Casting to primitive types
To → From ↓ |
byte |
short |
char |
int |
long |
float |
double |
boolean |
---|---|---|---|---|---|---|---|---|
byte |
≈ | ω | ωη | ω | ω | ω | ω | - |
short |
η | ≈ | η | ω | ω | ω | ω | - |
char |
η | η | ≈ | ω | ω | ω | ω | - |
int |
η | η | η | ≈ | ω | ω | ω | - |
long |
η | η | η | η | ≈ | ω | ω | - |
float |
η | η | η | η | η | ≈ | ω | - |
double |
η | η | η | η | η | η | ≈ | - |
boolean |
- | - | - | - | - | - | - | ≈ |
Byte |
⊗ | ⊗,ω | - | ⊗,ω | ⊗,ω | ⊗,ω | ⊗,ω | - |
Short |
- | ⊗ | - | ⊗,ω | ⊗,ω | ⊗,ω | ⊗,ω | - |
Character |
- | - | ⊗ | ⊗,ω | ⊗,ω | ⊗,ω | ⊗,ω | - |
Integer |
- | - | - | ⊗ | ⊗,ω | ⊗,ω | ⊗,ω | - |
Long |
- | - | - | - | ⊗ | ⊗,ω | ⊗,ω | - |
Float |
- | - | - | - | - | ⊗ | ⊗,ω | - |
Double |
- | - | - | - | - | - | ⊗ | - |
Boolean |
- | - | - | - | - | - | - | ⊗ |
Object |
⇓,⊗ | ⇓,⊗ | ⇓,⊗ | ⇓,⊗ | ⇓,⊗ | ⇓,⊗ | ⇓,⊗ | ⇓,⊗ |
Table 5.5-B. Casting to reference types
To → From ↓ |
Byte |
Short |
Character |
Integer |
Long |
Float |
Double |
Boolean |
Object |
---|---|---|---|---|---|---|---|---|---|
byte |
⊕ | - | - | - | - | - | - | - | ⊕,⇑ |
short |
- | ⊕ | - | - | - | - | - | - | ⊕,⇑ |
char |
- | - | ⊕ | - | - | - | - | - | ⊕,⇑ |
int |
- | - | - | ⊕ | - | - | - | - | ⊕,⇑ |
long |
- | - | - | - | ⊕ | - | - | - | ⊕,⇑ |
float |
- | - | - | - | - | ⊕ | - | - | ⊕,⇑ |
double |
- | - | - | - | - | - | ⊕ | - | ⊕,⇑ |
boolean |
- | - | - | - | - | - | - | ⊕ | ⊕,⇑ |
Byte |
≈ | - | - | - | - | - | - | - | ⇑ |
Short |
- | ≈ | - | - | - | - | - | - | ⇑ |
Character |
- | - | ≈ | - | - | - | - | - | ⇑ |
Integer |
- | - | - | ≈ | - | - | - | - | ⇑ |
Long |
- | - | - | - | ≈ | - | - | - | ⇑ |
Float |
- | - | - | - | - | ≈ | - | - | ⇑ |
Double |
- | - | - | - | - | - | ≈ | - | ⇑ |
Boolean |
- | - | - | - | - | - | - | ≈ | ⇑ |
Object |
⇓ | ⇓ | ⇓ | ⇓ | ⇓ | ⇓ | ⇓ | ⇓ | ≈ |
Example 5.5-1. Casting for Reference Types
class Point { int x, y; }
interface Colorable { void setColor(int color); }
class ColoredPoint extends Point implements Colorable {
int color;
public void setColor(int color) { this.color = color; }
}
final class EndPoint extends Point {}
class Test {
public static void main(String[] args) {
Point p = new Point();
ColoredPoint cp = new ColoredPoint();
Colorable c;
// The following may cause errors at run time because
// we cannot be sure they will succeed; this possibility
// is suggested by the casts:
cp = (ColoredPoint)p; // p might not reference an
// object which is a ColoredPoint
// or a subclass of ColoredPoint
c = (Colorable)p; // p might not be Colorable
// The following are incorrect at compile time because
// they can never succeed as explained in the text:
Long l = (Long)p; // compile-time error #1
EndPoint e = new EndPoint();
c = (Colorable)e; // compile-time error #2
}
}
Here, the first compile-time error occurs because the class types Long
and Point
are unrelated (that is, they are not the same, and neither is a subclass of the other), so a cast between them will always fail.
The second compile-time error occurs because a variable of type EndPoint
can never reference a value that implements the interface Colorable
. This is because EndPoint
is a final
type, and a variable of a final
type always holds a value of the same run-time type as its compile-time type. Therefore, the run-time type of variable e
must be exactly the type EndPoint
, and type EndPoint
does not implement Colorable
.
Example 5.5-2. Casting for Array Types
class Point {
int x, y;
Point(int x, int y) { this.x = x; this.y = y; }
public String toString() { return "("+x+","+y+")"; }
}
interface Colorable { void setColor(int color); }
class ColoredPoint extends Point implements Colorable {
int color;
ColoredPoint(int x, int y, int color) {
super(x, y); setColor(color);
}
public void setColor(int color) { this.color = color; }
public String toString() {
return super.toString() + "@" + color;
}
}
class Test {
public static void main(String[] args) {
Point[] pa = new ColoredPoint[4];
pa[0] = new ColoredPoint(2, 2, 12);
pa[1] = new ColoredPoint(4, 5, 24);
ColoredPoint[] cpa = (ColoredPoint[])pa;
System.out.print("cpa: {");
for (int i = 0; i < cpa.length; i++)
System.out.print((i == 0 ? " " : ", ") + cpa[i]);
System.out.println(" }");
}
}
This program compiles without errors and produces the output:
cpa: { (2,2)@12, (4,5)@24, null, null }
Example 5.5-3. Casting Incompatible Types at Run Time
class Point { int x, y; }
interface Colorable { void setColor(int color); }
class ColoredPoint extends Point implements Colorable {
int color;
public void setColor(int color) { this.color = color; }
}
class Test {
public static void main(String[] args) {
Point[] pa = new Point[100];
// The following line will throw a ClassCastException:
ColoredPoint[] cpa = (ColoredPoint[])pa;
System.out.println(cpa[0]);
int[] shortvec = new int[2];
Object o = shortvec;
// The following line will throw a ClassCastException:
Colorable c = (Colorable)o;
c.setColor(0);
}
}
This program uses casts to compile, but it throws exceptions at run time, because the types are incompatible.
Chapter 6: Names
6.1 Declarations
A declaration introduces an entity into a program and includes an identifier (3.8) that can be used in a name to refer to this entity. The identifier is constrained to be a type identifier when the entity being introduced is a class, interface, or type parameter.
A declared entity is one of the following:
A module, declared in a
module
declaration (7.7)A package, declared in a
package
declaration (7.4)An imported type, declared in a single-type-import declaration or a type-import-on-demand declaration (7.5.1, 7.5.2)
An imported
static
member, declared in a single-static-import declaration or a static-import-on-demand declaration (7.5.3, 7.5.4)A class, declared in a class type declaration (8.1)
An interface, declared in an interface type declaration (9.1)
A type parameter, declared as part of the declaration of a generic class, interface, method, or constructor (8.1.2, 9.1.2, 8.4.4, 8.8.4)
A member of a reference type (8.2, 9.2, 8.9.3, 9.6, 10.7), one of the following:
An enum constant (8.9)
A field, one of the following:
A method, one of the following:
A parameter, one of the following:
A formal parameter of a method or constructor of a class type or enum type (8.4.1, 8.8.1, 8.9.2), or of a lambda expression (15.27.1)
A formal parameter of an
abstract
method of an interface type or annotation type (9.4, 9.6.1)An exception parameter of an exception handler declared in a
catch
clause of atry
statement (14.20)
A local variable, one of the following:
A pattern variable, declared in a pattern (14.30).
Constructors (8.8) are also introduced by declarations, but use the name of the class in which they are declared rather than introducing a new name.
The declaration of a type which is not generic (class C ...
) declares one entity: a non-generic type (C
). A non-generic type is not a raw type, despite the syntactic similarity. In contrast, the declaration of a generic type (class C<T> ...
or interface C<T> ...
) declares two entities: a generic type (C<T>
) and a corresponding non-generic type (C
). In this case, the meaning of the term C
depends on the context where it appears:
If genericity is unimportant, as in the non-generic contexts identified below, the identifier
C
denotes the non-generic typeC
.If genericity is important, as in all contexts from 6.5 except the non-generic contexts, the identifier
C
denotes either:
The 14 non-generic contexts are as follows:
In a
uses
orprovides
directive in a module declaration (7.7.1)In a single-type-import declaration (7.5.1)
To the left of the
.
in a single-static-import declaration (7.5.3)To the left of the
.
in a static-import-on-demand declaration (7.5.4)To the left of the
(
in a constructor declaration (8.8)After the
@
sign in an annotation (9.7)To the left of
.class
in a class literal (15.8.2)To the left of
.this
in a qualifiedthis
expression (15.8.4)To the left of
.super
in a qualified superclass field access expression (15.11.2)To the left of
.
Identifier or.super.
Identifier in a qualified method invocation expression (15.12)To the left of
.super::
in a method reference expression (15.13)In a qualified expression name in a postfix expression or a
try
-with-resources statement (15.14.1, 14.20.3)In a
throws
clause of a method or constructor (8.4.6, 8.8.5, 9.4)In an exception parameter declaration (14.20)
The first eleven non-generic contexts correspond to the first eleven syntactic contexts for a TypeName in 6.5.1. The twelfth non-generic context is where a qualified ExpressionName such as C.x
may include a TypeName C
to denote static member access. The common use of TypeName in these twelve contexts is significant: it indicates that these contexts involve a less-than-first-class use of a type. In contrast, the thirteenth and fourteenth non-generic contexts employ ClassType, indicating that throws
and catch
clauses use types in a first-class way, in line with, say, field declarations. The characterization of these two contexts as non-generic is due to the fact that an exception type cannot be parameterized.
Note that the ClassType production allows annotations, so it is possible to annotate the use of a type in a
throws
orcatch
clause, whereas the TypeName production disallows annotations, so it is not possible to annotate the name of a type in, say, a single-type-import declaration.
Naming Conventions
The class libraries of the Java SE Platform attempt to use, whenever possible, names chosen according to the conventions presented below. These conventions help to make code more readable and avoid certain kinds of name conflicts.
We recommend these conventions for use in all programs written in the Java programming language. However, these conventions should not be followed slavishly if long-held conventional usage dictates otherwise. So, for example, the
sin
andcos
methods of the classjava.lang.Math
have mathematically conventional names, even though these method names flout the convention suggested here because they are short and are not verbs.
Package Names and Module Names
Developers should take steps to avoid the possibility of two published packages having the same name by choosing unique package names for packages that are widely distributed. This allows packages to be easily and automatically installed and catalogued. This section specifies a suggested convention for generating such unique package names. Implementations of the Java SE Platform are encouraged to provide automatic support for converting a set of packages from local and casual package names to the unique name format described here.
If unique package names are not used, then package name conflicts may arise far from the point of creation of either of the conflicting packages. This may create a situation that is difficult or impossible for the user or programmer to resolve. The classes
ClassLoader
andModuleLayer
can be used to isolate packages with the same name from each other in those cases where the packages will have constrained interactions, but not in a way that is transparent to a naïve program.
You form a unique package name by first having (or belonging to an organization that has) an Internet domain name, such as
oracle.com
. You then reverse this name, component by component, to obtain, in this example,com.oracle
, and use this as a prefix for your package names, using a convention developed within your organization to further administer package names. Such a convention might specify that certain package name components be division, department, project, machine, or login names.
Example 6.1-1. Unique Package Names
com.nighthacks.scrabble.dictionary
org.openjdk.compiler.source.tree
net.jcip.annotations
edu.cmu.cs.bovik.cheese
gov.whitehouse.socks.mousefinder
The first component of a unique package name is always written in all-lowercase ASCII letters and should be one of the top level domain names, such as
com
,edu
,gov
,mil
,net
, ororg
, or one of the English two-letter codes identifying countries as specified in ISO Standard 3166.
In some cases, the Internet domain name may not be a valid package name. Here are some suggested conventions for dealing with these situations:
If the domain name contains a hyphen, or any other special character not allowed in an identifier (3.8), convert it into an underscore.
If any of the resulting package name components are keywords (3.9), append an underscore to them.
If any of the resulting package name components start with a digit, or any other character that is not allowed as an initial character of an identifier, have an underscore prefixed to the component.
The name of a module should correspond to the name of its principal exported package. If a module does not have such a package, or if for legacy reasons it must have a name that does not correspond to one of its exported packages, then its name should still start with the reversed form of an Internet domain with which its author is associated.
Example 6.1-2. Unique Module Names
com.nighthacks.scrabble
org.openjdk.compiler
net.jcip.annotations
The first component of a package or module name must not be the identifier
java
. Package and module names that start with the identifierjava
are reserved for packages and modules of the Java SE Platform.
The name of a package or module is not meant to imply where the package or module is stored on the Internet. For example, a package named
edu.cmu.cs.bovik.cheese
is not necessarily obtainable from the hostcmu.edu
orcs.cmu.edu
orbovik.cs.cmu.edu
. The suggested convention for generating unique package and module names is merely a way to piggyback a package and module naming convention on top of an existing, widely known unique name registry instead of having to create a separate registry for package and module names.
Class and Interface Type Names
Names of class types should be descriptive nouns or noun phrases, not overly long, in mixed case with the first letter of each word capitalized.
Example 6.1-3. Descriptive Class Names
`ClassLoader`
SecurityManager
`Thread`
Dictionary
BufferedInputStream
Likewise, names of interface types should be short and descriptive, not overly long, in mixed case with the first letter of each word capitalized. The name may be a descriptive noun or noun phrase, which is appropriate when an interface is used as if it were an abstract superclass, such as interfaces
java.io.DataInput
andjava.io.DataOutput
; or it may be an adjective describing a behavior, as for the interfacesRunnable
andCloneable
.
Type Variable Names
Type variable names should be pithy (single character if possible) yet evocative, and should not include lower case letters. This makes it easy to distinguish type parameters from ordinary classes and interfaces.
Container types should use the name
E
for their element type. Maps should useK
for the type of their keys andV
for the type of their values. The nameX
should be used for arbitrary exception types. We useT
for type, whenever there is not anything more specific about the type to distinguish it. (This is often the case in generic methods.)
If there are multiple type parameters that denote arbitrary types, one should use letters that neighbor
T
in the alphabet, such asS
. Alternately, it is acceptable to use numeric subscripts (e.g.,T1
,T2
) to distinguish among the different type variables. In such cases, all the variables with the same prefix should be subscripted.
If a generic method appears inside a generic class, it is a good idea to avoid using the same names for the type parameters of the method and class, to avoid confusion. The same applies to nested generic classes.
Example 6.1-4. Conventional Type Variable Names
When type parameters do not fall conveniently into one of the categories mentioned, names should be chosen to be as meaningful as possible within the confines of a single letter. The names mentioned above (
E
,K
,V
,X
,T
) should not be used for type parameters that do not fall into the designated categories.
Method Names
Method names should be verbs or verb phrases, in mixed case, with the first letter lowercase and the first letter of any subsequent words capitalized. Here are some additional specific conventions for method names:
Methods to get and set an attribute that might be thought of as a variable V should be named
get*V*
andset*V*
. An example is the methodsgetPriority
andsetPriority
of classThread
.A method that returns the length of something should be named
length
, as in classString
.A method that tests a boolean condition V about an object should be named
is*V*
. An example is the methodisInterrupted
of classThread
.A method that converts its object to a particular format F should be named
to*F*
. Examples are the methodtoString
of classObject
and the methodstoLocaleString
andtoGMTString
of classjava.util.Date
.
Whenever possible and appropriate, basing the names of methods in a new class on names in an existing class that is similar, especially a class from the Java SE Platform API, will make it easier to use.
Field Names
Names of fields that are not
final
should be in mixed case with a lowercase first letter and the first letters of subsequent words capitalized. Note that well-designed classes have very fewpublic
orprotected
fields, except for fields that are constants (static
final
fields).
Fields should have names that are nouns, noun phrases, or abbreviations for nouns.
Examples of this convention are the fields
buf
,pos
, andcount
of the classjava.io.ByteArrayInputStream
and the fieldbytesTransferred
of the classjava.io.InterruptedIOException
.
Constant Names
The names of constants in interface types should be, and
final
variables of class types may conventionally be, a sequence of one or more words, acronyms, or abbreviations, all uppercase, with components separated by underscore "_
" characters. Constant names should be descriptive and not unnecessarily abbreviated. Conventionally they may be any appropriate part of speech.
Examples of names for constants include
MIN_VALUE
,MAX_VALUE
,MIN_RADIX
, andMAX_RADIX
of the classCharacter
.
A group of constants that represent alternative values of a set, or, less frequently, masking bits in an integer value, are sometimes usefully specified with a common acronym as a name prefix.
For example:
interface ProcessStates { int PS_RUNNING = 0; int PS_SUSPENDED = 1; }
Local Variable and Parameter Names
Local variable and parameter names should be short, yet meaningful. They are often short sequences of lowercase letters that are not words, such as:
Acronyms, that is the first letter of a series of words, as in
cp
for a variable holding a reference to aColoredPoint
Abbreviations, as in
buf
holding a pointer to a buffer of some kindMnemonic terms, organized in some way to aid memory and understanding, typically by using a set of local variables with conventional names patterned after the names of parameters to widely used classes. For example:
in
andout
, whenever some kind of input and output are involved, patterned after the fields ofSystem
off
andlen
, whenever an offset and length are involved, patterned after the parameters to theread
andwrite
methods of the interfacesDataInput
andDataOutput
ofjava.io
One-character local variable or parameter names should be avoided, except for temporary and looping variables, or where a variable holds an undistinguished value of a type. Conventional one-character names are:
b
for abyte
c
for achar
d
for adouble
e
for anException
f
for afloat
i
,j
, andk
forint
sl
for along
o
for anObject
s
for aString
v
for an arbitrary value of some type
Local variable or parameter names that consist of only two or three lowercase letters should not conflict with the initial country codes and domain names that are the first component of unique package names.
6.3 Scope of a Declaration
The scope of a declaration is the region of the program within which the entity declared by the declaration can be referred to using a simple name, provided it is not shadowed (6.4.1).
A declaration is said to be in scope at a particular point in a program if and only if the declaration's scope includes that point.
The scope of the declaration of an observable top level package (7.4.3) is all observable compilation units associated with modules to which the package is uniquely visible (7.4.3).
The declaration of a package that is not observable is never in scope.
The declaration of a subpackage is never in scope.
The package java
is always in scope.
The scope of a type imported by a single-type-import declaration (7.5.1) or a type-import-on-demand declaration (7.5.2) is the module declaration (7.7) and all the class and interface type declarations (7.6) of the compilation unit in which the import
declaration appears, as well as any annotations on the module declaration or package declaration of the compilation unit.
The scope of a member imported by a single-static-import declaration (7.5.3) or a static-import-on-demand declaration (7.5.4) is the module declaration and all the class and interface type declarations of the compilation unit in which the import
declaration appears, as well as any annotations on the module declaration or package declaration of the compilation unit.
The scope of a top level type (7.6) is all type declarations in the package in which the top level type is declared.
The scope of a declaration of a member m declared in or inherited by a class type C (8.1.6) is the entire body of C, including any nested type declarations.
The scope of a declaration of a member m declared in or inherited by an interface type I (9.1.4) is the entire body of I, including any nested type declarations.
The scope of an enum constant C declared in an enum type T is the body of T, and any case
label of a switch
statement whose expression is of enum type T (14.11).
The scope of a formal parameter of a method (8.4.1), constructor (8.8.1), or lambda expression (15.27) is the entire body of the method, constructor, or lambda expression.
The scope of a class's type parameter (8.1.2) is the type parameter section of the class declaration, the type parameter section of any superclass or superinterface of the class declaration, and the class body.
The scope of an interface's type parameter (9.1.2) is the type parameter section of the interface declaration, the type parameter section of any superinterface of the interface declaration, and the interface body.
The scope of a method's type parameter (8.4.4) is the entire declaration of the method, including the type parameter section, but excluding the method modifiers.
The scope of a constructor's type parameter (8.8.4) is the entire declaration of the constructor, including the type parameter section, but excluding the constructor modifiers.
The scope of a local class declaration immediately enclosed by a block (14.2) is the rest of the immediately enclosing block, including its own class declaration.
The scope of a local class declaration immediately enclosed by a switch block statement group (14.11) is the rest of the immediately enclosing switch block statement group, including its own class declaration.
The scope of a local variable declaration in a block (14.4) is the rest of the block in which the declaration appears, starting with its own initializer and including any further declarators to the right in the local variable declaration statement.
The scope of a local variable declared in the ForInit part of a basic for
statement (14.14.1) includes all of the following:
Its own initializer
Any further declarators to the right in the ForInit part of the
for
statementThe Expression and ForUpdate parts of the
for
statementThe contained Statement
The scope of a local variable declared in the FormalParameter part of an enhanced for
statement (14.14.2) is the contained Statement.
The scope of a parameter of an exception handler that is declared in a catch
clause of a try
statement (14.20) is the entire block associated with the catch
.
The scope of a variable declared in the ResourceSpecification of a try
-with-resources statement (14.20.3) is from the declaration rightward over the remainder of the ResourceSpecification and the entire try
block associated with the try
-with-resources statement.
The translation of a
try
-with-resources statement implies the rule above.
Example 6.3-1. Scope of Type Declarations
These rules imply that declarations of class and interface types need not appear before uses of the types. In the following program, the use of PointList
in class Point
is valid, because the scope of the class declaration PointList
includes both class Point
and class PointList
, as well as any other type declarations in other compilation units of package points
.
Example 6.3-2. Scope of Local Variable Declarations
The following program causes a compile-time error because the initialization of local variable x
is within the scope of the declaration of local variable x
, but the local variable x
does not yet have a value and cannot be used. The field x
has a value of 0
(assigned when Test1
was initialized) but is a red herring since it is shadowed (6.4.1) by the local variable x
.
The following program does compile:
class Test2 {
static int x;
public static void main(String[] args) {
int x = (x=2)*2;
System.out.println(x);
}
}
because the local variable x
is definitely assigned (16) before it is used. It prints:
4
In the following program, the initializer for three
can correctly refer to the variable two
declared in an earlier declarator, and the method invocation in the next line can correctly refer to the variable three
declared earlier in the block.
class Test3 {
public static void main(String[] args) {
System.out.print("2+1=");
int two = 2, three = two + 1;
System.out.println(three);
}
}
This program produces the output:
2+1=3
A variable declared in a pattern is known as a pattern variable (14.30). Pattern variables differ from other local variables in that they can only be assigned a value by pattern matching (14.30.3). This process is conditional; a pattern variable is only assigned a value if the pattern match succeeds.
Accordingly the scope of pattern variables is carefully defined so that a pattern variable is only in scope at those program points where pattern matching will have succeeded and the pattern variable will have been definitely assigned a value. Put another way, accessing a pattern variable where pattern matching can not be guaranteed to have succeeded is not possible and will result in a compile-time error.
In this sense, the scope of a pattern variable is a flow dependent concept similar to definite assignment (Chapter 16). The rules that are defined in the rest of this section deliberately have a similar form to those used in Chapter 16.
The scope of a pattern variable is determined by considering the innermost enclosing statement S that contains the pattern variable declaration. The overall scope of a pattern variable V is defined to be (i) those expressions and statements contained in S where V is definitely matched; and (ii) if S is immediately contained by a statement Q, those statements following S contained by Q where V is definitely matched; and (iii) if S is immediately contained by a block, those statements following S contained by that block where V is definitely matched.
The remainder of this section is devoted to a precise explanation of the words "definitely matched at", for which we define three auxiliary technical terms:
- a pattern variable is introduced by an expression when true;
- a pattern variable is introduced by an expression when false; and
- a pattern variable is introduced by a statement.
The analysis takes into account the structure of statements and expressions, with a special treatment for the boolean expression operators and certain statement forms.
The simplest example is that the pattern variable
s
is introduced by the expressiona instanceof String s
when true. In other words, if the value of the expression istrue
then the pattern matching must have succeeded, and thus the pattern variable must have been assigned a value.In contrast, the pattern variable
t
is introduced by the expression!(b instanceof Integer t)
when false. This is because the pattern matching could only have succeeded if the value of the expression isfalse
.Pattern variables can, in certain circumstances, be introduced by a statement. Further details are given in 6.3.2.
6.3.1 Pattern Declaration Scopes and Expressions
Only certain boolean expressions can introduce a new pattern variable into scope. If an expression is not a logical complement expression, conditional-and expression, conditional-or expression, conditional expression, or instanceof
operator, then no rules apply regarding the introduction of pattern variables.
6.3.1.1 Conditional-And Operator &&
The following rules apply to a conditional-and expression (15.23):
- V is introduced by
a && b
when true iff either- V is introduced by
a
when true, or - V is introduced by
b
when true.
a
when true, and V is introduced byb
when true. - V is introduced by
A pattern variable introduced by
a
when true is definitely matched atb
.It is a compile-time error if any pattern variable introduced by
a
when true is already in scope atb
.
The first rule rules out the possibility of a pattern variable being implicitly assigned a value more than once by pattern matching. Pattern variables are implicitly final by design.
The second rule means that a pattern variable introduced by the left-hand operand of a conditional-and operator is in scope, and can therefore be used, in the right-hand operand. This allows for expressions such as
x instanceof String s && s.length()>0
.
It is a compile-time error if a pattern variable is both introduced by
a
when false, and byb
when false.This final case rules out an example such as the following where a pattern variable is declared in more than one place but these declarations are coalesced by the context:
As it stands the pattern variable
t
is not in scope in the second contained statement (the one after theelse
), but this may be relaxed in future versions of the language (provided the types are identical).
6.3.1.2 Conditional-Or Operator ||
The following rules apply to a conditional-or expression (15.24):
V is introduced by
a || b
when false iff either- V is introduced by
a
when false, or - V is introduced by
b
when false.
It is a compile-time error if both V is introduced by
a
when false, and V is introduced byb
when false.- V is introduced by
A pattern variable introduced by
a
when false is definitely matched atb
.It is a compile-time error if any pattern variable introduced by
a
when false is already in scope atb
.
It is a compile-time error if a pattern variable is both introduced by
a
when true, and byb
when true.This final case rules out an example such as the following:
As it stands the pattern variable
t
is not in scope in the first contained statement, but this may be relaxed in future versions of the language.
6.3.1.3 Logical Complement Operator !
The following rules apply to a logical complement expression (15.15.6):
V is introduced by
!a
when true iff V is introduced bya
when false.V is introduced by
!a
when false iff V is introduced bya
when true.
6.3.1.4 Conditional Operator ? :
The following rules apply to a conditional expression a ? b : c
(15.25):
A pattern variable introduced by
a
when true is definitely matched atb
.It is a compile-time error if any pattern variable introduced by
a
when true is already in scope atb
.A pattern variable introduced by
a
when false is definitely matched atc
.It is a compile-time error if any pattern variable introduced by
a
when false is already in scope atc
.It is a compile-time error if any of the following conditions hold:
A pattern variable is introduced both by
a
when true, and byc
when true.A pattern variable is introduced both by
a
when false, and byb
when true.A pattern variable is introduced both by
b
when true, and byc
when true.A pattern variable is introduced both by
a
when true, and byc
when false.A pattern variable is introduced both by
a
when false, and byb
when false.A pattern variable is introduced both by
b
when false, and byc
when false.
These final cases are to rule out cases of the introduction of pattern variables that may be supported in future versions of the language.
6.3.1.5 instanceof
Operator
The following rule applies to an instanceof
expression (15.20.2):
V is introduced by
a instanceof p
when true iff V is declared by patternp
. (The rules for determining which pattern variables are declared by a pattern are given in 14.30.1.)It is a compile-time error if any pattern variable introduced by the pattern
p
is already in scope at theinstanceof
expression.
Note that no pattern variable is introduced by an expression
e instanceof p
when false.
JEP 361 proposes to add a switch
expression. This would result in the following additional rule for determining the scope of pattern variables (in conjunction with the changes required to specify switch
expressions).
6.3.1.6 switch
Expressions
The following rule covers the switch
expression (15.28).
- A pattern variable introduced by a statement S contained in a switch labeled statement group (14.11.1) is definitely matched at all the statements following S, if any, in the switch labeled statement group.
6.3.2 Pattern Declaration Scopes and Statements
Only a few statements play a significant role in determining the scope of pattern variables.
The scope of pattern variables declared in subexpressions contained within if
, while
, do
, and for
statements can, in certain circumstances, include other contained substatements. Here is an example:
if (x instanceof String s) {
// String s in scope for this block
// No explicit cast needed here!
...
System.out.println("The string value was: " + s);
} else {
// String s not in scope here
System.out.println(s); // Compile-time error!
}
In certain constrained circumstances, a pattern variable can be introduced by a statement. In this case, the pattern variable is in scope at following statements in the enclosing block. Here is an example:
6.3.2.1 Blocks
The following rule applies to a block statement S contained in a block that is not a switch block:
- A pattern variable introduced by S is definitely matched at all the block statements following S, if any, in the block.
6.3.2.2 if
Statements
The following rules apply to a statement if (e) S
(14.9.1):
A pattern variable introduced by
e
when true is definitely matched atS
.It is a compile-time error if any pattern variable introduced by
e
when true is already in scope atS
.V is introduced by
if (e) S
iff V is introduced bye
when false andS
cannot complete normally.It is a compile-time error if any pattern variable introduced by the
if
statement is already in scope.
The second rule makes use of the notion of 'cannot complete normally' (14.21), which itself makes use of the concept of a constant expression (15.29). This means that calculating the scope of a pattern variable may require determining whether a simple name, or a qualified name of the form TypeName
.
Identifier, refers to a constant variable. As pattern variables can never refer to a constant variable, there is no circularity.
The following rules apply to a statement if (e) S else T
(14.9.2):
A pattern variable introduced by
e
when true is definitely matched atS
.It is a compile-time error if any pattern variable introduced by
e
when true is already in scope atS
.A pattern variable introduced by
e
when false is definitely matched atT
.It is a compile-time error if any pattern variable introduced by
e
when false is already in scope atT
.- V is introduced by
if (e) S else T
iff either:- V is introduced by
e
when true,S
can complete normally, andT
cannot complete normally; or - V is introduced by
e
when false,S
cannot complete normally, andT
can complete normally.
It is a compile-time error if any pattern variable introduced by the
if
statement is already in scope. - V is introduced by
These rules highlight the flow-like nature of scoping for pattern variables. In the following statement:
The pattern variable
s
is introduced by theinstanceof
operator and is in scope in the first contained statement (the one before theelse
keyword), but it is not in scope in the second contained statement (the one after theelse
keyword).
Moreover, combined with the treatment for the boolean expressions, the scope of pattern variables is robust against code refactorings that exploit the familar boolean logical equivalences. For example, the previous code can be rewritten as:
And, furthermore, can be rewritten as:
6.3.2.3 while
Statements
The following rules apply to a statement while (e) S
(14.12):
A pattern variable introduced by
e
when true is definitely matched atS
.It is a compile-time error if any pattern variable introduced by
e
when true is already in scope atS
.V is introduced by
while (e) S
iff V is introduced bye
when false, and S does not contains a reachablebreak
statement whose break target contains S.It is a compile-time error if any pattern variable introduced by the
while
statement is already in scope.
6.3.2.4 do
Statements
The following rule applies to a statement do S while (e)
(14.13):
V is introduced by
do S while (e)
iff V is introduced bye
when false, andS
does not contain a reachablebreak
statement whose break target containsS
.It is a compile-time error if any pattern variable introduced by the
do
statement is already in scope.
6.3.2.5 for
Statements
The following rules cover the basic for
statement (14.14.1). Since the enhanced for
statement (14.14.2) is defined by translation to a basic for
statement, no special rules need to be provided for it.
A pattern variable introduced by the condition expression when true is definitely matched at both the incrementation part and the contained statement.
It is a compile-time error if any pattern variable introduced by the condition expression is already in scope at the incrementation part or the contained statement.
V is introduced by a
for
statement iff V is introduced by the condition expression when false, and the contained statement, S, does not contain a reachablebreak
statement whose break target contains S.It is a compile-time error if any pattern variable introduced by a
for
statement is already in scope.
6.3.2.6 switch
Statements
The following rule covers the switch
statement (14.11).
- A pattern variable introduced by a statement S contained in a switch block statement group (14.11) is definitely matched at all the statements following S, if any, in the switch block statement group.
6.4 Shadowing and Obscuring
A local variable (14.4), formal parameter (8.4.1, 15.27.1), exception parameter (14.20), and local class (14.3), and pattern variable (14.30) can only be referred to using a simple name, not a qualified name (6.2).
Some declarations are not permitted within the scope of a local variable, pattern variable, formal parameter, exception parameter, or local class declaration because it would be impossible to distinguish between the declared entities using only simple names.
For example, if the name of a formal parameter of a method could be redeclared as the name of a local variable in the method body, then the local variable would shadow the formal parameter and there would be no way to refer to the formal parameter - an undesirable outcome.
It is a compile-time error if the name of a formal parameter is used to declare a new variable within the body of the method, constructor, or lambda expression, unless the new variable is declared within a class declaration contained by the method, constructor, or lambda expression.
It is a compile-time error if the name of a local variable v is used to declare a new variable within the scope of v, unless the new variable is declared within a class whose declaration is within the scope of v.
It is a compile-time error if the name of an exception parameter is used to declare a new variable within the Block of the catch
clause, unless the new variable is declared within a class declaration contained by the Block of the catch
clause.
It is a compile-time error if the name of a local class C is used to declare a new local class within the scope of C, unless the new local class is declared within another class whose declaration is within the scope of C.
These rules allow redeclaration of a variable or local class in nested class declarations that occur in the scope of the variable or local class; such nested class declarations may be local classes (14.3) or anonymous classes (15.9). Thus, the declaration of a formal parameter, local variable, pattern variable, or local class may be shadowed in a class declaration nested within a method, constructor, or lambda expression; and the declaration of an exception parameter may be shadowed in a class declaration nested within the Block of the
catch
clause.
There are two design alternatives for handling name clashes created by lambda parameters and other variables declared in lambda expressions. One is to mimic class declarations: like local classes, lambda expressions introduce a new "level" for names, and all variable names outside the expression can be redeclared. Another is a "local" strategy: like
catch
clauses,for
loops, and blocks, lambda expressions operate at the same "level" as the enclosing context, and local variables outside the expression cannot be shadowed. The above rules use the local strategy; there is no special dispensation that allows a variable declared in a lambda expression to shadow a variable declared in an enclosing method.
Note that the rule for local classes does not make an exception for a class of the same name declared within the local class itself. However, this case is prohibited by a separate rule: a class cannot have the same name as a class that encloses it (8.1).
Example 6.4-1. Attempted Shadowing Of A Local Variable
Because a declaration of an identifier as a local variable of a method, constructor, or initializer block must not appear within the scope of a parameter, or local variable, or pattern variable of the same name, a compile-time error occurs for the following program:
class Test1 {
public static void main(String[] args) {
int i;
for (int i = 0; i < 10; i++)
System.out.println(i);
}
}
This restriction helps to detect some otherwise very obscure bugs. A similar restriction on shadowing of members by local variables was judged impractical, because the addition of a member in a superclass could cause subclasses to have to rename local variables. Related considerations make restrictions on shadowing of local variables by members of nested classes, or on shadowing of local variables by local variables declared within nested classes unattractive as well.
Hence, the following program compiles without error:
class Test2 {
public static void main(String[] args) {
int i;
class Local {
{
for (int i = 0; i < 10; i++)
System.out.println(i);
}
}
new Local();
}
}
On the other hand, local variables with the same name may be declared in two separate blocks or for
statements, neither of which contains the other:
class Test3 {
public static void main(String[] args) {
for (int i = 0; i < 10; i++)
System.out.print(i + " ");
for (int i = 10; i > 0; i--)
System.out.print(i + " ");
System.out.println();
}
}
This program compiles without error and, when executed, produces the output:
0 1 2 3 4 5 6 7 8 9 10 9 8 7 6 5 4 3 2 1
This style is also common with pattern matching, where repeated type test patterns often employ the same pattern name:
class Test4 {
class Point {
int x, y;
}
public static void test(Object a, Object b, Object c) {
if (a instanceof Point p) {
System.out.print("a is a point (" + p.x + ", " + p.y);
}
if (b instanceof Point p){
System.out.print("b is a point (" + p.x + ", " + p.y);
} else if (c instanceof Point p) {
System.out.print("c is a point (" + p.x + ", " + p.y);
}
System.out.println();
}
}
However, pattern variables are not allowed to shadow other pattern variables; a compile-time error occurs for the following program:
class Test5 {
public static void test(Object a, Object b, Object c) {
if (a instanceof Point p) {
System.out.print("a is a point (" + p.x + ", " + p.y);
if (b instanceof Point p){
System.out.print("b is a point (" + p.x + ", " + p.y);
}
}
System.out.println();
}
}
Pattern variables are, like local variables, not allowed to shadow local variables; a compile-time error occurs for the following program:
6.4.1 Shadowing
Some declarations may be shadowed in part of their scope by another declaration of the same name, in which case a simple name cannot be used to refer to the declared entity.
Shadowing is distinct from hiding (8.3, 8.4.8.2, 8.5, 9.3, 9.5), which applies only to members which would otherwise be inherited but are not because of a declaration in a subclass. Shadowing is also distinct from obscuring (6.4.2).
A declaration d of a type named n shadows the declarations of any other types named n that are in scope at the point where d occurs throughout the scope of d.
A declaration d of a field or formal parameter named n shadows, throughout the scope of d, the declarations of any other variables named n that are in scope at the point where d occurs.
A declaration d of a local variable, pattern variable, or exception parameter named n shadows, throughout the scope of d, (a) the declarations of any other fields named n that are in scope at the point where d occurs, and (b) the declarations of any other variables named n that are in scope at the point where d occurs but are not declared in the innermost class in which d is declared.
A declaration d of a method named n shadows the declarations of any other methods named n that are in an enclosing scope at the point where d occurs throughout the scope of d.
A package declaration never shadows any other declaration.
A type-import-on-demand declaration never causes any other declaration to be shadowed.
A static-import-on-demand declaration never causes any other declaration to be shadowed.
A single-type-import declaration d in a compilation unit c of package p that imports a type named n shadows, throughout c, the declarations of:
any top level type named n declared in another compilation unit of p
any type named n imported by a type-import-on-demand declaration in c
any type named n imported by a static-import-on-demand declaration in c
A single-static-import declaration d in a compilation unit c of package p that imports a field named n shadows the declaration of any static field named n imported by a static-import-on-demand declaration in c, throughout c.
A single-static-import declaration d in a compilation unit c of package p that imports a method named n with signature s shadows the declaration of any static method named n with signature s imported by a static-import-on-demand declaration in c, throughout c.
A single-static-import declaration d in a compilation unit c of package p that imports a type named n shadows, throughout c, the declarations of:
any static type named n imported by a static-import-on-demand declaration in c;
any top level type (7.6) named n declared in another compilation unit (7.3) of p;
any type named n imported by a type-import-on-demand declaration (7.5.2) in c.
Example 6.4.1-1. Shadowing of a Field Declaration by a Local Variable Declaration
class Test {
static int x = 1;
public static void main(String[] args) {
int x = 0;
System.out.print("x=" + x);
System.out.println(", Test.x=" + Test.x);
}
}
This program produces the output:
x=0, Test.x=1
This program declares:
a class
Test
a class (
static
) variablex
that is a member of the classTest
a class method
main
that is a member of the classTest
a parameter
args
of themain
methoda local variable
x
of themain
method
Since the scope of a class variable includes the entire body of the class (8.2), the class variable x
would normally be available throughout the entire body of the method main
. In this example, however, the class variable x
is shadowed within the body of the method main
by the declaration of the local variable x
.
A local variable has as its scope the rest of the block in which it is declared (6.3); in this case this is the rest of the body of the main
method, namely its initializer "0
" and the invocations of System.out.print
and System.out.println
.
This means that:
The expression
x
in the invocation ofprint
refers to (denotes) the value of the local variablex
.The invocation of
println
uses a qualified name (6.6)Test.x
, which uses the class type nameTest
to access the class variablex
, because the declaration ofTest.x
is shadowed at this point and cannot be referred to by its simple name.
The keyword this
can also be used to access a shadowed field x
, using the form this.x
. Indeed, this idiom typically appears in constructors (8.8):
class Pair {
Object first, second;
public Pair(Object first, Object second) {
this.first = first;
this.second = second;
}
}
Here, the constructor takes parameters having the same names as the fields to be initialized. This is simpler than having to invent different names for the parameters and is not too confusing in this stylized context. In general, however, it is considered poor style to have local variables with the same names as fields.
Example 6.4.1-2. Shadowing of a Type Declaration by Another Type Declaration
import java.util.*;
class Vector {
int val[] = { 1 , 2 };
}
class Test {
public static void main(String[] args) {
Vector v = new Vector();
System.out.println(v.val[0]);
}
}
The program compiles and prints:
1
using the class Vector
declared here in preference to the generic class java.util.Vector
(8.1.2) that might be imported on demand.
6.4.2 Obscuring
A simple name may occur in contexts where it may potentially be interpreted as the name of a variable, a type, or a package. In these situations, the rules of 6.5.2 specify that a variable will be chosen in preference to a type, and that a type will be chosen in preference to a package. Thus, it is may sometimes be impossible to refer to a type or package via its simple name, even though its declaration is in scope and not shadowed. We say that such a declaration is obscured.
Obscuring is distinct from shadowing (6.4.1) and hiding (8.3, 8.4.8.2, 8.5, 9.3, 9.5).
There is no obscuring between the name of a module and the name of a variable, type, or package; thus, modules may share names with variables, types, and packages, though it is not necessarily recommended to name a module after a package it contains.
The naming conventions of 6.1 help reduce obscuring, but if it does occur, here are some notes about what you can do to avoid it.
When package names occur in expressions:
If a package name is obscured by a field declaration, then
import
declarations (7.5) can usually be used to make available the type names declared in that package.If a package name is obscured by a declaration of a parameter or local variable, then the name of the parameter or local variable can be changed without affecting other code.
The first component of a package name is normally not easily mistaken for a type name, as a type name normally begins with a single uppercase letter. (The Java programming language does not actually rely on case distinctions to determine whether a name is a package name or a type name.)
Obscuring involving class and interface type names is rare. Names of fields, parameters, and local variables normally do not obscure type names because they conventionally begin with a lowercase letter whereas type names conventionally begin with an uppercase letter.
Method names cannot obscure or be obscured by other names (6.5.7).
Obscuring involving field names is rare; however:
If a field name obscures a package name, then an
import
declaration (7.5) can usually be used to make available the type names declared in that package.If a field name obscures a type name, then a fully qualified name for the type can be used unless the type name denotes a local class (14.3).
Field names cannot obscure method names.
If a field name is shadowed by a declaration of a parameter or local variable, then the name of the parameter or local variable can be changed without affecting other code.
Obscuring involving constant names is rare:
Constant names normally have no lowercase letters, so they will not normally obscure names of packages or types, nor will they normally shadow fields, whose names typically contain at least one lowercase letter.
Constant names cannot obscure method names, because they are distinguished syntactically.
6.5 Determining the Meaning of a Name
6.5.1 Syntactic Classification of a Name According to Context
A name is syntactically classified as a ModuleName in these contexts:
In a
requires
directive in a module declaration (7.7.1)To the right of
to
in anexports
oropens
directive in a module declaration (7.7.2)
A name is syntactically classified as a PackageName in these contexts:
To the right of
exports
oropens
in a module declarationTo the left of the "
.
" in a qualified PackageName
A name is syntactically classified as a TypeName in these contexts:
The first eleven non-generic contexts (6.1):
In a
uses
orprovides
directive in a module declaration (7.7.1)In a single-type-import declaration (7.5.1)
To the left of the
.
in a single-static-import declaration (7.5.3)To the left of the
.
in a static-import-on-demand declaration (7.5.4)To the left of the
(
in a constructor declaration (8.8)After the
@
sign in an annotation (9.7)To the left of
.class
in a class literal (15.8.2)To the left of
.this
in a qualifiedthis
expression (15.8.4)To the left of
.super
in a qualified superclass field access expression (15.11.2)To the left of
.
Identifier or.super.
Identifier in a qualified method invocation expression (15.12)To the left of
.super::
in a method reference expression (15.13)
As the Identifier or dotted Identifier sequence that constitutes any ReferenceType (including a ReferenceType to the left of the brackets in an array type, or to the left of the < in a parameterized type, or in a non-wildcard type argument of a parameterized type, or in an
extends
orsuper
clause of a wildcard type argument of a parameterized type) in the 16 contexts where types are used (4.11):In an
extends
orimplements
clause of a class declaration (8.1.4, 8.1.5, 8.5, 9.5)In an
extends
clause of an interface declaration (9.1.3)The return type of a method (8.4, 9.4) (including the type of an element of an annotation type (9.6.1))
In the
throws
clause of a method or constructor (8.4.6, 8.8.5, 9.4)In an
extends
clause of a type parameter declaration of a generic class, interface, method, or constructor (8.1.2, 9.1.2, 8.4.4, 8.8.4)The type in a field declaration of a class or interface (8.3, 9.3)
The type in a formal parameter declaration of a method, constructor, or lambda expression (8.4.1, 8.8.1, 9.4, 15.27.1)
The type of the receiver parameter of a method (8.4)
The type in a local variable declaration (14.4, 14.14.1, 14.14.2, 14.20.3)
A type in an exception parameter declaration (14.20)
In an explicit type argument list to an explicit constructor invocation statement or class instance creation expression or method invocation expression (8.8.7.1, 15.9, 15.12)
In an unqualified class instance creation expression, either as the class type to be instantiated (15.9) or as the direct superclass or direct superinterface of an anonymous class to be instantiated (15.9.5)
The element type in an array creation expression (15.10.1)
The type in the cast operator of a cast expression (15.16)
The type that follows the
instanceof
relational operator (15.20.2)In a method reference expression (15.13), as the reference type to search for a member method or as the class type or array type to construct.
The extraction of a TypeName from the identifiers of a ReferenceType in the 16 contexts above is intended to apply recursively to all sub-terms of the ReferenceType, such as its element type and any type arguments.
For example, suppose a field declaration uses the type
p.q.Foo[]
. The brackets of the array type are ignored, and the termp.q.Foo
is extracted as a dotted sequence of Identifiers to the left of the brackets in an array type, and classified as a TypeName. A later step determines which ofp
,q
, andFoo
is a type name or a package name.As another example, suppose a cast operator uses the type
p.q.Foo<? extends String>
. The termp.q.Foo
is again extracted as a dotted sequence of Identifier terms, this time to the left of the<
in a parameterized type, and classified as a TypeName. The termString
is extracted as an Identifier in anextends
clause of a wildcard type argument of a parameterized type, and classified as a TypeName.
A name is syntactically classified as an ExpressionName in these contexts:
As the qualifying expression in a qualified superclass constructor invocation (8.8.7.1)
As the qualifying expression in a qualified class instance creation expression (15.9)
As the array reference expression in an array access expression (15.10.3)
As a PostfixExpression (15.14)
As the left-hand operand of an assignment operator (15.26)
As a PatternVariable in a pattern (14.30)
As a VariableAccess in a
try
-with-resources statement (14.20.3)
A name is syntactically classified as a MethodName in this context:
- Before the "
(
" in a method invocation expression (15.12)
A name is syntactically classified as a PackageOrTypeName in these contexts:
To the left of the "
.
" in a qualified TypeNameIn a type-import-on-demand declaration (7.5.2)
A name is syntactically classified as an AmbiguousName in these contexts:
To the left of the "
.
" in a qualified ExpressionNameTo the left of the rightmost
.
that occurs before the "(
" in a method invocation expressionTo the left of the "
.
" in a qualified AmbiguousNameIn the default value clause of an annotation type element declaration (9.6.2)
To the right of an "
=
" in an an element-value pair (9.7.1)To the left of
::
in a method reference expression (15.13)
The effect of syntactic classification is to restrict certain kinds of entities to certain parts of expressions:
The name of a field, parameter, or local variable may be used as an expression (15.14.1).
The name of a method may appear in an expression only as part of a method invocation expression (15.12).
The name of a class or interface type may appear in an expression only as part of a class literal (15.8.2), a qualified
this
expression (15.8.4), a class instance creation expression (15.9), an array creation expression (15.10.1), a cast expression (15.16), aninstanceof
expression (15.20.2), an enum constant (8.9), or as part of a qualified name for a field or method.The name of a package may appear in an expression only as part of a qualified name for a class or interface type.
6.5.2 Reclassification of Contextually Ambiguous Names
An AmbiguousName is then reclassified as follows.
If the AmbiguousName is a simple name, consisting of a single Identifier:
If the Identifier appears within the scope (6.3) of a local variable declaration (14.4) or pattern variable declaration (14.30.1) or parameter declaration (8.4.1, 8.8.1, 14.20) or field declaration (8.3) with that name, then the AmbiguousName is reclassified as an ExpressionName.
Otherwise, if a field of that name is declared in the compilation unit (7.3) containing the Identifier by a single-static-import declaration (7.5.3), or by a static-import-on-demand declaration (7.5.4) then the AmbiguousName is reclassified as an ExpressionName.
Otherwise, if the Identifier is a valid TypeIdentifier and appears within the scope (6.3) of a top level class (8) or interface type declaration (9), a local class declaration (14.3) or member type declaration (8.5, 9.5) with that name, then the AmbiguousName is reclassified as a TypeName.
Otherwise, if the Identifier is a valid TypeIdentifier and a type of that name is declared in the compilation unit (7.3) containing the Identifier, either by a single-type-import declaration (7.5.1), or by a type-import-on-demand declaration (7.5.2), or by a single-static-import declaration (7.5.3), or by a static-import-on-demand declaration (7.5.4), then the AmbiguousName is reclassified as a TypeName.
Otherwise, the AmbiguousName is reclassified as a PackageName. A later step determines whether or not a package of that name actually exists.
If the AmbiguousName is a qualified name, consisting of a name, a ".
", and an Identifier, then the name to the left of the ".
" is first reclassified, for it is itself an AmbiguousName. There is then a choice:
If the name to the left of the "
.
" is reclassified as a PackageName, then:If the Identifier is a valid TypeIdentifier, and there is a package whose name is the name to the left of the "
.
", and that package contains a declaration of a type whose name is the same as the Identifier, then this AmbiguousName is reclassified as a TypeName.Otherwise, this AmbiguousName is reclassified as a PackageName. A later step determines whether or not a package of that name actually exists.
If the name to the left of the "
.
" is reclassified as a TypeName, then:If the Identifier is the name of a method or field of the type denoted by TypeName, then this AmbiguousName is reclassified as an ExpressionName.
Otherwise, if the Identifier is a valid TypeIdentifier and is the name of a member type of the type denoted by TypeName, then this AmbiguousName is reclassified as a TypeName.
Otherwise, a compile-time error occurs.
If the name to the left of the "
.
" is reclassified as an ExpressionName, then this AmbiguousName is reclassified as an ExpressionName. A later step determines whether or not a member with the name Identifier actually exists.
The requirement that a potential type name be "a valid TypeIdentifier" prevents treating
var
as a type name. It is usually redundant, because the rules for declarations already prevent the introduction of types namedvar
. However, in some cases, a compiler may find a binary class namedvar
, and we want to be clear that such classes can never be named. The simplest solution is to consistently check for a valid TypeIdentifier.
Example 6.5.2-1. Reclassification of Contextually Ambiguous Names
Consider the following contrived "library code":
package org.rpgpoet;
import java.util.Random;
public interface Music { Random[] wizards = new Random[4]; }
and then consider this example code in another package:
First of all, the name org.rpgpoet.Music.wizards.length
is classified as an ExpressionName because it functions as a PostfixExpression. Therefore, each of the names:
is initially classified as an AmbiguousName. These are then reclassified:
The simple name
org
is reclassified as a PackageName (since there is no variable or type named org in scope).Next, assuming that there is no class or interface named
rpgpoet
in any compilation unit of packageorg
(and we know that there is no such class or interface because packageorg
has a subpackage namedrpgpoet
), the qualified nameorg.rpgpoet
is reclassified as a PackageName.Next, because package
org.rpgpoet
has an accessible (6.6) interface type namedMusic
, the qualified nameorg.rpgpoet.Music
is reclassified as a TypeName.Finally, because the name
org.rpgpoet.Music
is a TypeName, the qualified nameorg.rpgpoet.Music.wizards
is reclassified as an ExpressionName.
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, 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 (8.3.1.1), the expression name must appear within an instance method (8.4.3.2), instance variable initializer (8.3.2), instance initializer (8.6), or constructor (8.8). If the expression name appears within a class method, class variable initializer, or static initializer (8.7), then a compile-time error occurs.
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, pattern 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, pattern 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
Chapter 9: Interfaces
9.6 Annotation Types
9.6.4 Predefined Annotation Types
9.6.4.1 @Target
An annotation of type java.lang.annotation.Target
is used on the declaration of an annotation type T to specify the contexts in which T is applicable. java.lang.annotation.Target
has a single element, value
, of type java.lang.annotation.ElementType[]
, to specify contexts.
Annotation types may be applicable in declaration contexts, where annotations apply to declarations, or in type contexts, where annotations apply to types used in declarations and expressions.
There are nine declaration contexts, each corresponding to an enum constant of java.lang.annotation.ElementType
:
Module declarations (7.7)
Corresponds to
java.lang.annotation.ElementType.MODULE
Package declarations (7.4.1)
Corresponds to
java.lang.annotation.ElementType.PACKAGE
Type declarations: class, interface, enum, and annotation type declarations (8.1.1, 9.1.1, 8.5, 9.5, 8.9, 9.6)
Corresponds to
java.lang.annotation.ElementType.TYPE
Additionally, annotation type declarations correspond to
java.lang.annotation.ElementType.ANNOTATION_TYPE
Method declarations (including elements of annotation types) (8.4.3, 9.4, 9.6.1)
Corresponds to
java.lang.annotation.ElementType.METHOD
Constructor declarations (8.8.3)
Corresponds to
java.lang.annotation.ElementType.CONSTRUCTOR
Type parameter declarations of generic classes, interfaces, methods, and constructors (8.1.2, 9.1.2, 8.4.4, 8.8.4)
Corresponds to
java.lang.annotation.ElementType.TYPE_PARAMETER
Field declarations (including enum constants) (8.3.1, 9.3, 8.9.1)
Corresponds to
java.lang.annotation.ElementType.FIELD
Formal and exception parameter declarations (8.4.1, 9.4, 14.20)
Corresponds to
java.lang.annotation.ElementType.PARAMETER
Local variable declarations (including loop variables of
for
statements,andresource variables oftry
-with-resources statements, and pattern variables) (14.4, 14.14.1, 14.14.2, 14.20.3, 15.20.2)Corresponds to
java.lang.annotation.ElementType.LOCAL_VARIABLE
There are 16 type contexts (4.11), all represented by the enum constant TYPE_USE
of java.lang.annotation.ElementType
.
It is a compile-time error if the same enum constant appears more than once in the value
element of an annotation of type java.lang.annotation.Target
.
If an annotation of type java.lang.annotation.Target
is not present on the declaration of an annotation type T, then T is applicable in all declaration contexts except type parameter declarations, and in no type contexts.
These contexts are the syntactic locations where annotations were allowed in Java SE 7.
Chapter 14: Blocks and Statements and Patterns
Sections 14.22-14.29 are left deliberately unused to allow for future language evolution.
14.30 Patterns
A pattern describes the shape of data. Pattern matching is the process of comparing a value against a pattern and determining whether the value matches the pattern or not. A pattern may in addition declare a pattern variable to name a component of the shape. If a value matches against a pattern, then this variable is assigned a value by the process of pattern matching. The treatment of scoping of pattern variables in 6.3.1 ensures that pattern variables are only in scope where matching is guaranteed to have succeeded and hence the pattern variable will be bound with a value at run-time.
14.30.1 Kinds of Patterns
- Pattern:
- TypeTestPattern
14.30.1.1 Type Test Pattern
- TypeTestPattern:
- ReferenceType Identifier
A type test pattern consists of a type and a pattern variable. It is a compile-time error if the type does not denote a reference type (4.3).
The type of a type test pattern is the ReferenceType.
A type test pattern is said to declare the pattern variable Identifier. The scope of that pattern variable Identifier is conditional on the context, as defined in 6.3. The type of the pattern variable Identifier is defined to be ReferenceType.
14.30.2 Compatibility of an Expression with a Pattern
An expression is compatible with a pattern as follows:
- The
null
literal is compatible with a type test pattern.
- An expression that is not the
null
literal is compatible with a type test pattern of type T if (i) the expression can be converted to type T by casting conversion (5.5), and (ii) the casting conversion does not make use of a narrowing reference conversion which is unchecked (5.1.6.2).
At compile time, the instanceof
operator (15.20.2) checks compatibility of its first operand, an expression, with the type of its second operand.
14.30.3 Execution of Pattern Matching
At run time, a value is matched against a pattern. If the value matches the pattern, then additionally values may be assigned to any pattern variables declared in the pattern. The rules for determining whether a value matches a pattern (or not) are as follows:
- The null reference value does not match a type test pattern.
- A value of reference type that is not the null reference value matches a type test pattern
T t
if the value could be cast toT
without raising aClassCastException
, in which case the value is assigned to the pattern variablet
; and it does not match otherwise.
All other possibilities are excluded by the compile time type-checking of pattern matching.
Chapter 15: Expressions
15.20 Relational Operators
The numerical comparison operators <
, >
, <=
, and >=
, and the instanceof
operator, are called the relational operators.
- RelationalExpression:
- ShiftExpression
- RelationalExpression
<
ShiftExpression - RelationalExpression
>
ShiftExpression - RelationalExpression
<=
ShiftExpression - RelationalExpression
>=
ShiftExpression - RelationalExpression
instanceof
ReferenceTypeReferenceTypeOrPattern
Patterns are defined in 14.30.
The relational operators are syntactically left-associative (they group left-to-right).
However, this fact is not useful. For example,
a<b<c
parses as(a<b)<c
, which is always a compile-time error, because the type ofa<b
is alwaysboolean
and < is not an operator onboolean
values.
The type of a relational expression is always boolean
.
15.20.2 Type Comparison Operator instanceof
The instanceof
Operator
instanceof
This subsection has a new title.
The type of the RelationalExpression operand of the instanceof
operator must be a reference type or the null type, or a compile-time error occurs.
It is a compile-time error if the ReferenceType mentioned after the instanceof
operator does not denote a reference type that is reifiable (4.7).
If a cast of the RelationalExpression to the ReferenceType would be rejected as a compile-time error (15.16), then the instanceof
relational expression likewise produces a compile-time error. In such a situation, the result of the instanceof
expression could never be true.
At run time, the result of the instanceof
operator is true
if the value of the RelationalExpression is not null
and the reference could be cast to the ReferenceType without raising a ClassCastException
. Otherwise the result is false
.
- ReferenceTypeOrPattern:
- ReferenceType
- Pattern
An instanceof
operator has one of two forms: (i) a type instanceof
operator, where the ReferenceTypeOrPattern operand is a ReferenceType; or (ii) a pattern instanceof
operator, where the ReferenceTypeOrPattern operand is a Pattern.
The following applies to a type instanceof
operator:
The type of the RelationalExpression operand of the type
instanceof
operator must be a reference type or the null type, or a compile-time error occurs.The expression RelationalExpression is compatible with the type ReferenceType if (i) RelationalExpression can be converted to type ReferenceType by casting conversion (5.5), and (ii) the casting conversion does not make use of a narrowing reference conversion which is unchecked (5.1.6.2). If RelationalExpression is not compatible with ReferenceType then a compile-time error occurs.
At run time, the result of the
instanceof
operator istrue
if the value of the RelationalExpression is notnull
and the reference could be cast to the ReferenceType without raising aClassCastException
. Otherwise the result isfalse
.
The following applies to a pattern instanceof
operator:
The type of the RelationalExpression operand of the pattern
instanceof
operator must be a reference type or the null type, or a compile-time error occurs.The RelationalExpression operand of a pattern
instanceof
operator must be compatible with the Pattern operand as defined in 14.30.2; otherwise, a compile-time error occurs.At run time, the value of the RelationalExpression is matched against the Pattern, as detailed in 14.30.3. If it matches then the result of the pattern
instanceof
operator istrue
, otherwise the result of the patterninstanceof
operator isfalse
Example 15.20.2-1. The type instanceof
Operator
class Point { int x, y; }
class Element { int atomicNumber; }
class Test {
public static void main(String[] args) {
Point p = new Point();
Element e = new Element();
if (e instanceof Point) { // compile-time error
System.out.println("I get your point!");
p = (Point)e; // compile-time error
}
}
}
This program results in two compile-time errors. The cast (Point)e
is incorrect because no instance of Element
or any of its possible subclasses (none are shown here) could possibly be an instance of any subclass of Point
. The instanceof
expression is incorrect for exactly the same reason. If, on the other hand, the class Point
were a subclass of Element
(an admittedly strange notion in this example):
then the cast would be possible, though it would require a run-time check, and the instanceof
expression would then be sensible and valid. The cast (Point)e
would never raise an exception because it would not be executed if the value of e
could not correctly be cast to type Point
.