java_language_specification_java_se_17_edition_chapter_6_-_names

Java Language Specification Java SE 17 Edition Chapter 6 - Names

Return to Java 17 Language Spec Table of Contents, Java 17 Language Spec, Java Language Specifications, Language Specifications, Java bibliography, Java DevOps, Java, Java topics, Awesome Java, Java development tools

“ (JSR-392 JvLngSpc17 2021)

Names

NAMES are used to refer to entities declared in a program.

A declared entity (§6.1) is a package, a class, an interface, a member (class, interface, field, or method) of a reference type, a type parameter, a formal parameter, an exception parameter, or a local variable.

Names in programs are either simple, consisting of a single identifier, or qualified, consisting of a sequence of identifiers separated by ”. “ tokens (§6.2).

Every declaration that introduces a name has a scoped (§6.3), which is the part of the program text within which the declared entity can be referred to by a simple name.

A qualified name]] N.x may be used to refer to a member of a package or reference type, where N is a simple or qualified name]] and x is an identifier. If N names a package, then x is a member of that package, which is either a class, an interface, or a subpackage. If N names a reference type or a variable of a reference type, then x names a member of that type, which is either a class, an interface, a field, or a method.

In determining the meaning of a name (§6.5), the context of the occurrence is used to disambiguate among packages, types, variables, and methods with the same name.

Access control (§6.6) can be specified in a class, interface, method, or field declaration to control when access to a member is allowed. Access is a different concept from scoped. Access specifies the part of the program text within which the declared entity can be referred to by a qualified name]]. Access to a declared entity is also relevant in a field access expression (§15.11), a method invocation expression in which the method is not specified by a simple name (§15.12), a method reference expression (§15.13), or a qualified class instance creation expression (§15.9). In the absence of an access modifier]], most declarations have package access, allowing access anywhere within the package that contains its declaration; other possibilities are public, protected, and private.

147

6.1

Declarations

NAMES

Fully qualified and canonical names (§6.7) are also discussed in this chapter.

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 avoid certain contextual keywords when the entity being introduced is a class, interface, or type parameter.

A declared entity is one of the following:

static-import-on-[[demand declaration (§7.5.3, §7.5.4)

(§8.9), or a record declaration (§8.10)

method, or constructor (§8.1.2, §9.1.2, §8.4.4, §8.8.4) 148

NAMES

Declarations

6.1

– A member class (§8.5, §9.5)

– A member interface (§8.5, §9.5)

– A field, one of the following:

› A field declared in a class (§8.3)

› A field declared in an interface (§9.3)

› An implicitly declared field of a class corresponding to an enum constant

or a record component

› The field length, which is implicitly a member of every array type (§10.7)

– A method, one of the following:

› A method (abstract or otherwise) declared in a class (§8.4)

› A method (abstract or otherwise) declared in an interface (§9.4)

› An implicitly declared accessor method corresponding to a record

component

– A formal parameter of a method of a class or interface (§8.4.1)

– A formal parameter of a constructor of a class (§8.8.1)

– A formal parameter of a lambda expression]] (§15.27.1)

a try statement]] (§14.20)

– A local variable declared by a local variable declaration statement in a block

(§14.4.2)

– A local variable declared by a for statement or a try-with-resources statement

(§14.14, §14.20.3)

– A local variable declared by a pattern (§14.30.1)

149

6.1

Declarations

NAMES

– A local class declared by a normal class declaration

– A local class declared by an enum declaration

– A local class declared by an record declaration

– A local interface declared by a normal interface declaration

Constructors (§8.8, §8.10.4) 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 generic class or interface (class C< T> … or interface C< T> …) introduces both a class named C and a family of types: the raw type C, the parameterized type C<Foo>, the parameterized type C<Bar>, etc.

When a reference to C occurs where genericity is unimportant, identified below as one of the non-generic contexts, the reference to C denotes the class or interface C. In other contexts, the reference to C denotes a type, or part of a type, introduced by C.

The 15 non-generic contexts are as follows:

1.

In a uses or provides directive in a module declaration (§7.7.1) 2.

In a single-type-import declaration (§7.5.1)

3.

To the left of the . in a single-static-import declaration (§7.5.3)

4.

To the left of the . in a static-import-on-[[demand declaration (§7.5.4) 5.

In a permits clause of a sealed class or interface declaration (§8.1.6, §9.1.4).

6.

To the left of the ( in a constructor declaration (§8.8)

7.

After the @ sign in an annotation (§9.7)

8.

To the left of .class in a class literal (§15.8.2)

9.

To the left of .this in a qualified this expression (§15.8.4)

10. To the left of .super in a qualified superclass field access expression (§15.11.2) 11. To the left of . Identifier or .super. Identifier in a qualified method invocation expression (§15.12)

12. To the left of .super:: in a method reference expression (§15.13)

13. In a qualified expression name in a postfix expression or a try-with-resources statement (§15.14.1, §14.20.3)

14. In a throws clause of a method or constructor (§8.4.6, §8.8.5, §9.4) 15. In an exception parameter declaration (§14.20)

The first twelve non-generic contexts correspond to the first twelve syntactic contexts for a TypeName in §6.5.1. The thirteenth non-generic context is where a qualified 150

NAMES

Declarations

6.1

ExpressionName such as C.x may include a TypeName C to denote static member access.

The common use of TypeName in these thirteen contexts is significant: it indicates that these contexts involve a less-than-first-class use of a type. In contrast, the fourteenth and fifteenth non-generic contexts employ ClassType, indicating that throws and catch clauses use types in a first-class way, in line with, for example, field declarations. The characterization of these two contexts as non-generic is due to the fact that an exception type cannot be

parameterized (§8.1.2).

Note that the ClassType production allows annotations, so it is possible to annotate the use of a type in a throws or catch clause, whereas the TypeName production disallows annotations, so it is not possible to annotate the name of a type in, for example, 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 and cos methods of the class java.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

Programmers 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 en[[couraged 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 and ModuleLayer 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.

151

6.1

Declarations

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, or org, 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:

identifier (§3.8), convert it into an underscore.

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 identifier java 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 host cmu.edu or cs.cmu.edu or bovik.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 Names

152

NAMES

Declarations

6.1

Names of class 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 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 and java.io.DataOutput; or it may be an adjective describing a behavior, as for the interfaces Runnable and Cloneable.

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 classes and interfaces should use the name E for their element type. Maps should use K for the type of their keys and V for the type of their values. The name X should be used for arbitrary exception types. We use T 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 as S. 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

public class HashSet<E> extends AbstractSet<E> { … }

public class HashMap]]<K,V> extends AbstractMap<K,V> { … }

public class ThreadLocal<T> { … }

public interface Functor<T, X extends Throwable> {

T eval() throws X;

}

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.

153

6.1

Declarations

NAMES

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:

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 few public or protected 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, and count of the class java.io.ByteArrayInputStream and the field bytesTransferred of the class

java.io.InterruptedIOException.

Constant Names

The names of constants in interfaces should be, and final variables of classes 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, and MAX_RADIX of the class Character.

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.

154

NAMES

Declarations

6.1

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:

– in and out, whenever some kind of input and output are involved, patterned

after the fields of System

– off and len, whenever an offset and length are involved, patterned after the parameters to the read and write methods of the interfaces DataInput and

DataOutput of java.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:

  • i, j, and k for ints

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.

155

6.2

Names and Identifiers

NAMES

6.2 Names and Identifiers

A name is used to refer to an entity declared in a program.

There are two forms of names: simple names and qualified name]]s.

A simple name is a single identifier.

A qualified name]] consists of a name, a ”.“ token, and an identifier.

In determining the meaning of a name (§6.5), the context in which the name appears is taken into account. The rules of §6.5 distinguish among contexts where a name must denote (refer to) a package (§6.5.3); a class, interface, or type parameter

(§6.5.5); a variable or value in an expression (§6.5.6); or a method (§6.5.7).

Packages, classes, interfaces, and type parameters have members which may be accessed by qualified name]]s. As background for the discussion of qualified name]]s and the determination of the meaning of names, see the descriptions of membership in §4.4, §4.5.2, §4.8, §4.9,

§7.1, §8.2, §9.2, and §10.7.

Not all identifiers in a program are a part of a name. Identifiers are also used in the following situations:

(§14.15, §14.16) that refer to statement labels.

The identifiers used in labeled]] statements and their associated break and continue statement]]s are completely separate from those used in declarations.

token, or the object denoted by the super or TypeName.super before the ”::“

token.

156

NAMES

Names and Identifiers

6.2

compile-time type of the expression preceding the new token.

In this program:

class Test {

public static void main(String[] args) {

Class c = System.out]].getClass();

System.out]].println(c.to[[String().length() +

args[0].length() + args.length);

}

}

the identifiers Test, main, and the first occurrences of args and c are not names. Rather, they are identifiers used in declarations to specify the names of the declared entities. The names String, Class, System.out]].getClass, System.out]].println, c.to[[String,

args, and args.length appear in the example.

The occurrence of length in args.length is a name because args.length is a qualified name]] (§6.5.6.2) and not a field access expression (§15.11). A field access expression, as well as a method invocation expression, a method reference expression, and a qualified class instance creation expression, uses an identifier rather than a name to denote the member of interest. Thus, the occurrence of length in args[0].length() is not a name, but rather an identifier appearing in a method invocation expression.

One might wonder why these kinds of expression use an identifier rather than a simple name, which is after all just an identifier. The reason is that a simple expression name is defined in terms of the lexical environment; that is, a simple expression name must be in the scoped of a variable declaration (§6.5.6.1). On the other hand, field access, qualified method invocation, method references, and qualified class instance creation all refer to members whose names are not in the lexical environment. By definition, such names are bound only in the context provided by the Primary of the field access expression, method invocation expression, method reference expression, or class instance creation expression; or by the super of the field access expression, method invocation expression, or method reference expression; and so on. Thus, we denote such members with identifiers rather than simple names.

To complicate things further, a field access expression is not the only way to denote a field of an object. For parsing reasons, a qualified name]] is used to denote a field of an in-scoped variable. (The variable itself is denoted with a simple name, alluded to above.) It is necessary for access control (§6.6) to apply to both denotations of a field.

157

6.3

Scoped of a Declaration

NAMES

6.3 Scoped of a Declaration

The scoped 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 scoped at a particular point in a program if and only if the declaration's scoped includes that point.

The scoped 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 scoped.

The declaration of a subpackage is never in scoped.

The package java is always in scoped.

The scoped of a class or interface 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 declarations (§8.1, §9.1) 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 scoped 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 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 scoped of a top level class or interface (§7.6) is all class and interface declarations in the package in which the top level class or interface is declared.

The scoped of a declaration of a member m declared in or inherited by a class or interface C (§8.2, §9.2) is the entire body of C, including any nested class or interface declarations.

The scoped 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 scoped of a class's type parameter (§8.1.2) is the type parameter section of the class declaration, and the type parameter section of any superclass type or superinterface type of the class declaration, and the class body. If the class is a 158

NAMES

Scoped of a Declaration

6.3

record class (§8.10), then the scoped of the type parameter additionally includes the

header of the record declaration (§8.10.1).

The scoped of an interface's type parameter (§9.1.2) is the type parameter section of the interface declaration, and the type parameter section of any superinterface type of the interface declaration, and the interface body.

The scoped 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 scoped 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 scoped of a local class or interface declaration immediately enclosed by a block

(§14.2) is the rest of the immediately enclosing block, including the local class or interface declaration itself.

The scoped of a local class or interface declaration immediately enclosed by a switch block statement]] group (§14.11) is the rest of the immediately enclosing switch block statement]] group, including the local class or interface declaration itself.

The scoped of a local variable declared in a block by a local variable declaration statement (§14.4.2) is the rest of the block, starting with the declaration's own initializer and including any further declarators to the right in the local variable declaration statement.

The scoped of a local variable declared in the ForInit part of a basic for statement

(§14.14.1) includes all of the following:

The scoped of a local variable declared in the header of an enhanced for statement

(§14.14.2) is the contained Statement.

The scoped of a local variable declared in the resource specification of a try-with-resources statement (§14.20.3) is from the declaration rightward over the remainder of the resource specification and the entire try [[block associated with the try-with-resources statement.

The translation of a try-with-resources statement implies the rule above.

159

6.3

Scoped of a Declaration

NAMES

The scoped 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.

Example 6.3-1. Scoped of Class 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 scoped of the class declaration PointList includes both class Point and class PointList, as well as any other class or interface declarations in other compilation units of package points.

package points;

class Point {

int x, y;

PointList list;

Point next;

}

class PointList {

Point first;

}

Example 6.3-2. Scoped of Local Variable Declarations

The following program causes a compile-time error because the initialization of local variable x is within the scoped 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.

class Test1 {

static int x;

public static void main(String[] args) {

int x = 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 ( Definite Assignment)) before it is used. It prints:

4

160

NAMES

Scoped of a Declaration

6.3

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

The scoped of a pattern variable declaration (that is, a local variable declared by a pattern) is the part of the program that might be executed after the matching of a value against the pattern has succeeded (§14.30.2). It is determined by considering the program points where the pattern variable is definitely matched in a region beginning with the pattern that declares the pattern variable.

The remainder of this section is devoted to a precise explanation of the words

definitely matched“. The analysis takes into account the structure of statements and expressions, with a special treatment for the boolean expression operators and certain statement forms.

It will be seen that the scoped of a pattern variable declaration is a flow-dependent concept similar to definite assignment (§16 ( Definite Assignment)). The rules defined in the rest of this section deliberately have a similar form to the rules of definite assignment.

The analysis relies on the technical termintroduced by“, which has the following form:

The simplest example is that the pattern variable s is introduced by the expression a instanceof]] String s when true. In other words, if the value of the expression is true 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 is false.

161

6.3

Scoped of a Declaration

NAMES

6.3.1

Scoped for Pattern Variables in Expressions

Only certain kinds of boolean expressions are involved in introducing pattern variables and determining where those variables are definitely matched. If an expression is not a conditional-and expression, conditional-or expression, logical complement expression, conditional expression, instanceof]] expression, switch

expression, or parenthesized expression, then no scoped rules apply.

6.3.1.1

Conditional-And Operator &&

The following rules apply to a conditional-and expression a && b (§15.23):

It is a compile-time error if any pattern variable introduced by a when true is already in scoped at b.

It should be noted that there is no rule for introducing a pattern variable by a && b when false. This is because it cannot be determined at compile time which operand will evaluate to false.

It is a compile-time error if any of the following conditions hold:

These two error cases exclude the possibility of both operands of the && operator declaring a pattern variable of the same name. For example, consider the problematic expression (a instanceof]] String s) && (b instanceof]] String s). The first error case covers the entire expression evaluating to true, where (if the code were legal) two declarations of a pattern variable s would need to be initialized, given that both the left-hand operand and the right-hand operand evaluated to true. Since there is no way to distinguish the two variables called s in the rest of the program, the entire expression is considered erroneous.

The second error case covers the opposite scenario where the entire expression evaluates to false.

6.3.1.2

Conditional-Or Operator ||

The following rules apply to a conditional-or expression a || b (§15.24): 162

NAMES

Scoped of a Declaration

6.3

It is a compile-time error if any pattern variable introduced by a when false is already in scoped at b.

It should be noted that there is no rule for introducing a pattern variable by a || b when true. This is because it cannot be determined at compile time which operand will evaluate to true.

It is a compile-time error if any of the following conditions hold:

These two error cases exclude the possibility of both operands of the || operator declaring a pattern variable of the same name. For example, consider the problematic expression (a instanceof]] String s) || (b instanceof]] String s). The first error case covers the entire expression evaluating to true, where (if the code were legal) exactly one declaration of a pattern variable s would be initialized depending on whether the left-hand operand or the right-hand operand evaluated to true. Since it cannot be determined at compile time which operand will evaluate to true, and therefore which declaration of s will be initialized, the entire expression is considered erroneous. The second error case covers the opposite scenario where the entire expression evaluates to false.

6.3.1.3

Logical Complement Operator !

The following rules apply to a logical complement expression ! a (§15.15.6):

6.3.1.4

Conditional Operator ? :

The following rules apply to a conditional expression a ? b : c (§15.25):

It is a compile-time error if any pattern variable introduced by a when true is already in scoped at b.

163

6.3

Scoped of a Declaration

NAMES

It is a compile-time error if any pattern variable introduced by a when false is already in scoped at c.

It should be noted that there are no rules for introducing a pattern variable by a ? b : c when true or false. This is because it cannot be determined at compile time whether the operand a will evaluate to true.

It is a compile-time error if any of the following conditions hold:

These error cases are analogous to similar error cases for the && and || operators. They eliminate confusing cases where multiple declarations of the same pattern variable may occur across the operands of the ? : operator.

6.3.1.5

Pattern Match Operator instanceof]]

The following rules apply to an instanceof]] expression with a pattern operand, a instanceof]] p (§15.20.2):

by a pattern are given in §14.30.1.

It is a compile-time error if any pattern variable introduced by a instanceof]] p when true is already in scoped at the instanceof]] expression.

A pattern variable is not permitted to shadow another local variable (§6.4).

164

NAMES

Scoped of a Declaration

6.3

It should be noted that there is no rule for introducing a pattern variable by a instanceof]] p when false.

6.3.1.6

switch Expressions

The following rule applies to a switch expression]] (§15.28):

6.3.1.7

Parenthesized Expressions

The following rules apply to a parenthesized expression ( a) (§15.8.5):

6.3.2

Scoped for Pattern Variables in Statements

Only a few kinds of statements play a significant role in determining the scoped of pattern variables.

Where an if, while, do, or for statement contains an expression that introduces

pattern variables, the scoped of those variables can, in certain circumstances, include substatements of the statement.

For example, in the following if-then-else statement, the scoped of the pattern variable s includes one substatement but not another:

Object o = …

if (o instanceof]] String s)

// s in scoped for this substatement; no cast of o needed

System.out]].println(s.replace('*', '_'));

else

// s not in scoped for this substatement (hence, error)

System.out]].println(s);

Also, in certain circumstances, a pattern variable can be introduced by a statement itself, rather than by an expression within the statement. A pattern variable introduced by a statement is in scoped at the following statements in the enclosing block.

165

6.3

Scoped of a Declaration

NAMES

For example, in the following method, the scoped of the pattern variable s includes the method body following the if statement:

void test(Object o) {

if (!(o instanceof]] String s)) {

throw new IllegalArgumentException();

}

// This point is only reachable if the pattern match succeeded

// Thus, s is in scoped for the rest of the block

System.out]].println(s.repeat(5));

}

6.3.2.1

Blocks

The following rule applies to a block statement]] S contained in a block (§14.2) that

is not a switch block (§14.11.1):

6.3.2.2

if Statements

The following rules apply to a statement if ( e) S (§14.9.1):

It is a compile-time error if any pattern variable introduced by e when true is already in scoped at S.

It is a compile-time error if any pattern variable introduced by if ( e) S is already in scoped at the if statement.

The rule about an if-then statement introducing a pattern variable relies on the notion of “cannot complete normally” (§14.22), which in turn relies on the concept of a constant expression (§15.29). This means that calculating the scoped 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):

166

NAMES

Scoped of a Declaration

6.3

It is a compile-time error if any pattern variable introduced by e when true is already in scoped at S.

It is a compile-time error if any pattern variable introduced by e when false is already in scoped at T.

– It is introduced by e when true, and S can complete normally, and T cannot complete normally; or

– It is introduced by e when false, and S cannot complete normally, and T can complete normally.

It is a compile-time error if any pattern variable introduced by if ( e) S else T

is already in scoped at the if statement.

These rules highlight the flow-like nature of scoping for pattern variables. For example, in the following statement:

if (e instanceof]] String s) {

counter += s.length();

} else {

System.out]].println(e); // s not in scoped

}

The pattern variable s is introduced by the instanceof]] expression and is in scoped in the first contained statement (the assignment statement in the then block), but it is not in scoped in the second contained statement (the expression statement in the else block).

Moreover, combined with the treatment for boolean expressions, the scoped of pattern variables is robust against code refactorings that exploit the familar boolean logical equivalences. For example, the previous code can be rewritten as:

if (!(e instanceof]] String s)) {

System.out]].println(e); // s not in scoped

} else {

counter += s.length();

}

The code can even be rewritten as follows, though double use of the ! operator is not necessarily recommended:

167

6.3

Scoped of a Declaration

NAMES

if (!!(e instanceof]] String s)) {

counter += s.length();

} else {

System.out]].println(e); // s not in scoped

}

6.3.2.3

while Statement]]s

The following rules apply to a statement while ( e) S (§14.12):

It is a compile-time error if any pattern variable introduced by e when true is already in scoped at S.

It is a compile-time error if any pattern variable introduced by while ( e) S is already in scoped at the while statement]].

6.3.2.4

do Statements

The following rules apply to a statement do S while ( e) (§14.13):

It is a compile-time error if any pattern variable introduced by do S while ( e) is already in scoped at the do statement.

6.3.2.5

for Statements

The following rules apply to a basic for statement (§14.14.1):

It is a compile-time error if any pattern variable introduced by the condition expression]] when true is already in scoped at the incrementation part of the contained statement.

168

NAMES

Shadowing and Obscuring

6.4

It is a compile-time error if any pattern variable introduced by a basic for statement is already in scoped at the for statement.

An enhanced for statement (§14.14.2) is defined by translation to a basic for statement, so no special rules need to be provided for it.

6.3.2.6

switch Statement]]s

The following rule applies to a switch statement]] (§14.11):

6.3.2.7

Labeled]] Statements

The following rule applies to a labeled]] statement (§14.7):

6.4 Shadowing and Obscuring

A local variable (§14.4), formal parameter (§8.4.1, §8.8.1, §15.27.1), exception parameter (§14.20), local class, or local interface (§14.3) can only be referred to

using a simple name, not a qualified name]] (§6.2).

Some declarations are not permitted within the scoped of a local variable declaration, formal parameter declaration, exception parameter declaration, local [[class declaration, or local interface 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 169

6.4

Shadowing and Obscuring

NAMES

the new variable is declared within a class or interface 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 scoped of v, unless the new variable is declared within a class or interface declaration appearing within the scoped 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 or interface declaration contained by the Block of the catch clause.

It is a compile-time error if the name of a local class or interface C is used to declare a new local class or interface within the scoped of C, unless the new local class or interface is declared within a class or interface declaration appearing within the scoped of C.

These rules allow redeclaration of a variable, local class, or local interface in nested class or interface declarations that occur in the scoped of the variable, local class, or local interface; such nested class or interface declarations may be local class or interface declarations

(§14.3) or anonymous class declarations (§15.9.5). Thus, the declaration of a formal parameter, local variable, local class, or local interface may be shadowed in a class or interface declaration nested within a method, constructor, or lambda expression]]; and the declaration of an exception parameter may be shadowed in a class or interface 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 expression]]s. One is to mimic class declarations: like local classes, lambda expression]]s introduce a newlevel“ for names, and all variable names outside the expression can be redeclared. Another is a ”localstrategy: like catch clauses, for loops, and blocks, lambda expression]]s 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.

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 scoped of a parameter or local 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);

}

}

170

NAMES

Shadowing and Obscuring

6.4

This re[[striction]] helps to detect some otherwise very obscure bugs. A similar re[[striction]] 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 re[[striction]]s 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 patterns often employ the same name:

class Point {

int x, y;

Point(int x, int y) { this.x = x; this.y = y; }

}

class Test4 {

static void test(Object a, Object b, Object c) {

if (a instanceof]] Point p) {

System.out]].println(“a is a point (”+p.x+”,“+p.y+”)“); 171

6.4

Shadowing and Obscuring

NAMES

}

if (b instanceof]] Point p){

System.out]].println(“b is a point (”+p.x+”,“+p.y+”)“);

} else if (c instanceof]] Point p) {

System.out]].println(“c is a point (”+p.x+”,“+p.y+”)“);

}

}

public static void main(String[] args) {

Point p = new Point(2,3);

Point q = new Point(4,5);

Point r = new Point(6,7);

test(p, q, r);

}

}

However, pattern variables are not allowed to shadow local variables, including other pattern variables, so two compile-time errors occur for the following program:

class Point {

int x, y;

Point(int x, int y) { this.x = x; this.y = y; }

}

class Test5 {

static void test(Object a, Object b, Object c) {

if (a instanceof]] Point p) {

System.out]].println(“a is a point (”+p.x+”,“+p.y+”)“); if (b instanceof]] Point p) { // compile-time error

System.out]].println(“b is a point (”+p.x+”,“+p.y+”)“);

}

}

}

public static void main(String[] args) {

Point p = new Point(2,3);

Point q = new Point(4,5);

Point r = new Point(6,7);

test(p, q, r);

if (new Object() instanceof]] Point q) // compile-time error

System.out]].println(“I get your point”);

}

}

6.4.1

Shadowing

Some declarations may be shadowed in part of their scoped by another declaration of the same name, in which case a simple name cannot be used to refer to the declared entity.

172

NAMES

Shadowing and Obscuring

6.4

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 scoped at the point where d occurs throughout the scoped of d.

A declaration d of a field or formal parameter named n shadows, throughout the scoped of d, the declarations of any other variables named n that are in scoped at the point where d occurs.

A declaration d of a local variable or exception parameter named n shadows, throughout the scoped of d, (a) the declarations of any other fields named n that are in scoped at the point where d occurs, and (b) the declarations of any other variables named n that are in scoped 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 scoped at the point where d occurs throughout the scoped 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:

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.

173

6.4

Shadowing and Obscuring

NAMES

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:

of p;

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:

Since the scoped 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 scoped 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:

174

NAMES

Shadowing and Obscuring

6.4

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 scoped and not shadowed. We say that such a declaration is obscured.

175

6.4

Shadowing and Obscuring

NAMES

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:

can usually be used to make available the type names declared in that package.

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:

unless the type name denotes a local class or interface (§14.3).

Obscuring involving constant names is rare:

176

NAMES

Determining the Meaning of a Name

6.5

6.5 Determining the Meaning of a Name

The meaning of a name depends on the context in which it is used. The determination of the meaning of a name requires three steps:

TypeName and MethodName are less expressive than the other five categories, because they are denoted with TypeIdentifier and Un[[qualifiedMethodIdentifier,

respectively (§3.8).

ModuleName:

Identifier

ModuleName . Identifier

PackageName:

Identifier

PackageName . Identifier

TypeName:

TypeIdentifier

PackageOrTypeName . TypeIdentifier

PackageOrTypeName:

Identifier

PackageOrTypeName . Identifier

ExpressionName:

Identifier

AmbiguousName . Identifier

MethodName:

Un[[qualifiedMethodIdentifier

177

6.5

Determining the Meaning of a Name

NAMES

AmbiguousName:

Identifier

AmbiguousName . Identifier

The use of context helps to minimize name conflicts between entities of different kinds. Such conflicts will be rare if the naming conventions described in §6.1 are followed. Nevertheless, conflicts may arise unintentionally as types developed by different programmers or different organizations evolve. For example, types, methods, and fields may have the same name. It is always possible to distinguish between a method and a field with the same name, since the context of a use always tells whether a method is intended.

6.5.1

Syntactic Classification of a Name According to Context

A name is syntactically classified as a ModuleName in these contexts:

(§7.7.2)

A name is syntactically classified as a PackageName in these contexts:

A name is syntactically classified as a TypeName in these contexts:

178

NAMES

Determining the Meaning of a Name

6.5

1. In a uses or provides directive in a module declaration (§7.7.1)

2. In a single-type-import declaration (§7.5.1)

3. To the left of the . in a single-static-import declaration (§7.5.3) 4. To the left of the . in a static-import-on-[[demand declaration (§7.5.4) 5. In a permits clause of a sealed class or interface declaration (§8.1.6,

§9.1.4).

6. To the left of the ( in a constructor declaration (§8.8)

7. After the @ sign in an annotation (§9.7)

8. To the left of .class in a class literal (§15.8.2)

9. To the left of .this in a qualified this expression (§15.8.4)

10. To the left of .super in a qualified superclass field access expression

(§15.11.2)

11. To the left of . Identifier or .super. Identifier in a qualified method invocation expression (§15.12)

12. To the left of .super:: in a method reference expression (§15.13)

179

6.5

Determining the Meaning of a Name

NAMES

argument of a parameterized type) in the 17 contexts where types are used

(§4.11):

1. In an extends or implements clause of a class declaration (§8.1.4, §8.1.5)

2. In an extends clause of an interface declaration (§9.1.3) 3. The return type of a method (§8.4.5, §9.4), including the type of an element of an annotation interface (§9.6.1)

4. In the throws clause of a method or constructor (§8.4.6, §8.8.5, §9.4)

5. 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) 6. The type in a field declaration of a class or interface (§8.3, §9.3) 7. 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)

8. The type of the receiver parameter of a method (§8.4)

9. The type in a local variable declaration in either a statement (§14.4.2,

§14.14.1, §14.14.2, §14.20.3) or a pattern (§14.30.1)

10. A type in an exception parameter declaration (§14.20)

11. The type in a record component declaration of a record class (§8.10.1)

12. 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)

13. In an un[[qualified 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)

14. The element type in an array creation expression (§15.10.1)

15. The type in the cast operator of a cast expression (§15.16) 16. The type that follows the instanceof]] relational operator (§15.20.2) 17. 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.

180

NAMES

Determining the Meaning of a Name

6.5

For example, suppose a field declaration uses the type p.q.Foo[]. The brackets of the array type are ignored, and the term p.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 of p, q, and Foo is a type name or a package name.

As another example, suppose a cast operator uses the type p.q.Foo<? extends String>.

The term p.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 term String is extracted as an Identifier in an extends 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:

(§8.8.7.1)

(§15.9)

A name is syntactically classified as a MethodName in this context:

A name is syntactically classified as an AmbiguousName in these contexts:

6.5

Determining the Meaning of a Name

NAMES

The effect of syntactic classification is to re[[strict certain kinds of entities to certain parts of expressions:

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, then:

(§14.4, §8.4.1, §8.8.1, §15.27.1, §14.20, §8.3), then the AmbiguousName is reclassified as an ExpressionName.

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 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.

182

NAMES

Determining the Meaning of a Name

6.5

– 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.

The requirement that a potential type name be “a valid TypeIdentifierprevents treating var and yield as a type name. It is usually redundant, because the rules for declarations already prevent the introduction of types named var and yield. However, in some cases, a compiler may find a binary class named var or yield, 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:

package bazola;

class Gabriel {

static int n = org.rpgpoet.Music.wizards.length;

}

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: org.rpgpoet.Music.wizards

org.rpgpoet.Music

org.rpgpoet

org

is initially classified as an AmbiguousName. These are then reclassified:

183

6.5

Determining the Meaning of a Name

NAMES

6.5.3

Meaning of Module Names and Package Names

The module name M, whether simple or qualified, denotes the module (if any) with that name.

This section does not mandate a compile-time error if no module with that name is observable. Instead, the requires directive in a module declaration (§7.7.1) performs its own validation of the module name, while the exports and opens directives (§7.7.2) are tolerant of non-existent module names.

The meaning of a name classified as a PackageName is determined as follows.

6.5.3.1

Simple Package Names

If a package name consists of a single Identifier, then the identifier must occur in the scoped of exactly one declaration of a top level package with this name (§6.3), and that package must be uniquely visible to the current module (§7.4.3), or a compile-time error occurs. The meaning of the package name is that package.

6.5.3.2

Qualified Package Names

If a package name is of the form Q.Id, then Q must also be a package name. The package name Q.Id names a package that is the member named Id within the package named by Q.

If Q.Id does not name a package that is uniquely visible to the current module

(§7.4.3), then a compile-time error occurs.

6.5.4

Meaning of PackageOrTypeNames

6.5.4.1

Simple PackageOrTypeNames

If the PackageOrTypeName, Q, is a valid TypeIdentifier and occurs in the scoped of a class, interface, or type parameter named Q, then the PackageOrTypeName is reclassified as a TypeName.

184

NAMES

Determining the Meaning of a Name

6.5

Otherwise, the PackageOrTypeName is reclassified as a PackageName. The meaning of the PackageOrTypeName is the meaning of the reclassified name.

6.5.4.2

Qualified PackageOrTypeNames

Given a qualified PackageOrTypeName of the form Q.Id, if Id is a valid TypeIdentifier and the class, interface, type parameter, or package denoted by Q

has a member class or interface named Id, then the qualified PackageOrTypeName name is reclassified as a TypeName.

Otherwise, it is reclassified as a PackageName. The meaning of the qualified PackageOrTypeName is the meaning of the reclassified name.

6.5.5

Meaning of Type Names

The meaning of a name classified as a TypeName is determined as follows.

6.5.5.1

Simple Type Names

If a type name consists of a single Identifier, then the identifier must occur in the scoped of exactly one declaration of a class, interface, or type parameter with this

name (§6.3), or a compile-time error occurs.

If the declaration denotes a type parameter of a generic class or interface C (§8.1.2,

§9.1.2), then both of the following must be true, or a compile-time error occurs:

For example, the type name must not appear in the body of a static method declared by C, nor in the body of an instance method of a static class nested within C.

If the declaration denotes a type parameter of a generic method or constructor m

(§8.4.4, §8.8.4), and the type name appears directly or indirectly in the body of a local class, local interface, or anonymous class D declared directly in the body of m, then both of the following must be true, or a compile-time error occurs:

185

6.5

Determining the Meaning of a Name

NAMES

For example, the type name must not appear in the body of a static method declared by D, nor (if D is a local interface) in the body of a default method of D.

The meaning of the type name is the in-scoped class, interface, or type parameter.

Example 6.5.5.1-1. References to Type Parameters

class Box<T> {

T val;

Box(T t) { val = t; }

static Box<T> empty() { // compile-time error

return new Box<>(null);

}

static <U> Box<U> make(U val) {

interface Checker {

void check(U val); // compile-time error

}

class NullChecker implements Checker {

public void check(U val) {

if (val == null) {

throw new IllegalArgumentException();

}

}

}

new NullChecker().check(val);

return new Box<U>(val);

}

}

The class type parameter T is in scoped throughout the declaration of class Box; however, using the name T in the declaration of static method empty is illegal.

Similarly, the method type parameter U is in scoped throughout the declaration of method make; however, using the name U in the declaration of the (implicitly static) local interface Checker is illegal.

6.5.5.2

Qualified Type Names

If a type name is of the form Q.Id, then Q must be either the name of a class, interface, or type parameter in a package uniquely visible to the current module, or the name of a package uniquely visible to the current module (§7.4.3).

If Id names exactly one accessible class or interface (§6.6) that is a member of the class, interface, type parameter, or package denoted by Q, then the qualified type name denotes that class or interface.

186

NAMES

Determining the Meaning of a Name

6.5

If Id does not name a member class or interface within Q (§8.5, §9.5), or the member class or interface named Id within Q is not accessible, or Id names more than one member class or interface within Q, then a compile-time error occurs.

Example 6.5.5.2-1. Qualified Type Names

class Test {

public static void main(String[] args) {

java.[[util.Date date =

new java.[[util.Date(System.currentTimeMillis());

System.out]].println(date.toLocaleString());

}

}

This program produced]] the following output the first time it was run:

Sun Jan 21 22:56:29 1996

In this example, the name java.[[util.Date must denote a type, so we first use the procedure recursively to determine if java.[[util is an accessible class or interface or type parameter, or a package, which it is, and then we look to see if the class Date is accessible in this package.

6.5.6

Meaning of Expression Names

The meaning of a name classified as an ExpressionName is determined as follows.

6.5.6.1

Simple Expression Names

If an expression name consists of a single Identifier, then there must be exactly one declaration denoting either a local variable, formal parameter, exception parameter, or field in scoped at the point at which the identifier occurs. Otherwise, a compile-time error occurs.

If the declaration denotes an instance variable of a class C (§8.3.1.1), then both of the following must be true, or a compile-time error occurs:

name is an inner [[class of C.

For example, the expression name must not appear in the body of a static method declared by C, nor in the body of an instance method of a static class nested within C.

187

6.5

Determining the Meaning of a Name

NAMES

If the declaration denotes a local variable, formal parameter, or exception parameter, let X be the innermost method declaration, constructor declaration, instance initializer, static initializer, field declaration, or explicit constructor invocation statement which encloses the local variable or parameter declaration. If the expression name appears directly or indirectly in the body of a local class, local interface, or anonymous class D declared directly in X, then both of the following must be true, or a compile-time error occurs:

For example, the expression name must not appear in the body of a static method declared by D, nor (if D is a local interface) in the body of a default method of D.

If the declaration denotes a local variable, formal parameter, or exception parameter that is neither final nor effectively final (§4.12.4), it is a compile-time error if the expression name appears either in an inner [[class enclosed directly or indirectly by X, or in a lambda expression]] contained by X (§15.27).

The net effect of these rules is that a local variable, formal parameter, or exception parameter can only be referenced from a nested class or interface declared within its scoped if (i) the reference is not within a static context, (ii) there is a chain of inner (non-static) classes from the reference to the variable declaration, and (iii) the variable is final or effectively final. References from lambda expression]]s also require the variable to be final or effectively final.

If the declaration declares a final variable which is definitely assigned before the simple expression, the meaning of the name is the value of that variable. Otherwise, the meaning of the expression name is the variable declared by the declaration.

If the expression name appears in an assignment context, invocation context, or

casting context, then the type of the expression name is the declared type of the

field, local variable, or parameter after capture conversion (§5.1.10).

Otherwise, the type of the expression name is the declared type of the field, local variable or parameter.

That is, if the expression name appears “on the right-hand side”, its type is subject to capture conversion. If the expression name is a variable that appears “on the left-hand side”, its type is not subject to capture conversion.

Example 6.5.6.1-1. Simple Expression Names

class Test {

static int v;

188

NAMES

Determining the Meaning of a Name

6.5

static final int f = 3;

public static void main(String[] args) {

int i;

i = 1;

v = 2;

f = 33; // compile-time error

System.out]].println(i + ” “ + v + ” “ + f);

}

}

In this program, the names used as the left-hand-sides in the assignments to i, v, and f denote the local variable i, the field v, and the value of f (not the variable f, because f is a final variable). The example therefore produces an error at compile time because the last assignment does not have a variable as its left-hand side. If the erroneous assignment is removed, the modified code can be compiled and it will produce the output:

1 2 3

Example 6.5.6.1-2. References to Instance Variables

class Test {

static String a;

String b;

String concat1() {

return a + b;

}

static String concat2() {

return a + b; // compile-time error

}

int index() {

interface I {

class Matcher {

void check() {

if (a == null ||

b == null) { // compile-time error

throw new IllegalArgumentException();

}

}

int match(String s, String t) {

return s.indexOf(t);

}

}

}

I.Matcher matcher = new I.Matcher();

matcher.check();

return matcher.match(a, b);

}

}

189

6.5

Determining the Meaning of a Name

NAMES

The fields a and b are in scoped throughout the body of class Test. However, using the name b in the static context of the concat2 method, or in the declaration of the nested class Matcher that is not an inner [[class of Test, is illegal.

Example 6.5.6.1-3. References to Local Variables and Formal Parameters

class Test {

public static void main(String[] args) {

String first = args[0];

class Checker {

void checkWhitespace(int x) {

String arg = args[x];

if (!arg.trim().equals(arg)) {

throw new IllegalArgumentException();

}

}

static void checkFlag(int x) {

String arg = args[x]; // compile-time error

if (!arg.startsWith(”-“)) {

throw new IllegalArgumentException();

}

}

static void checkFirst() {

Runnable r = new Runnable() {

public void run() {

if (first == null) { // compile-time error

throw new IllegalArgumentException();

}

}

};

r.run();

}

}

final Checker c = new Checker();

c.checkFirst();

for (int i = 1; i < args.length; i++) {

Runnable r = () → {

c.checkWhitespace(i); // compile-time error

c.checkFlag(i); // compile-time error

};

}

}

}

The formal parameter args is in scoped throughout the body of method main. args is effectively final, so the name args can be used in the instance method checkWhitespace of local class Checker. However, using the name args in the static context of the checkFlag method of local class Checker is illegal.

190

NAMES

Determining the Meaning of a Name

6.5

The local variable first is in scoped for the remainder of the body of method main. first is also effectively final. However, the anonymous class declared in checkFirst is not an inner [[class of Checker, so using the name first in the anonymous class body is illegal.

(A lambda expression]] in the body of checkFirst would similarly be unable to refer to first, because the lambda expression]] would occur in a static context.)

The local variable c is in scoped for the last few lines of the body of method main, and is declared final, so the name c can be used in the body of the lambda expression]].

The local variable i is in scoped throughout the for loop. However, i is not effectively final, so using the name i in the body of the lambda expression]] is illegal.

6.5.6.2

Qualified Expression Names

If an expression name is of the form Q.Id, then Q has already been classified as a package name, a type name, or an expression name.

If Q is a package name, then a compile-time error occurs.

If Q is a type name that names a class type, then:

The type of the expression Q.Id is the declared type of the class variable after capture conversion (§5.1.10).

If Q.Id appears in a context that requires a variable and not a value, then a compile-time error occurs.

The type of the expression Q.Id is the declared type of the class variable after capture conversion (§5.1.10).

Note that this clause covers the use of enum constants (§8.9), since these always have a corresponding final class variable.

If Q is a type name that names an interface type, then:

191

6.5

Determining the Meaning of a Name

NAMES

The type of the expression Q.Id is the declared type of the field after capture

conversion (§5.1.10).

If Q.Id appears in a context that requires a variable and not a value, then a compile-time error occurs.

If Q is an expression name, let T be the type of the expression Q:

– A field of an interface type

– A final field of a class type (which may be either a class variable or an instance variable)

– The final field length of an array type (§10.7)

then Q.Id denotes the value of the field, unless it appears in a context that requires a variable and the field is a definitely unassigned blank final field, in which

case it yields a variable.

The type of the expression Q.Id is the declared type of the field after capture

conversion (§5.1.10).

If Q.Id appears in a context that requires a variable and not a value, and the field denoted by Q.Id is definitely assigned, then a compile-time error occurs.

The type of the expression Q.Id is the type of the field member after capture

conversion (§5.1.10).

Example 6.5.6.2-1. Qualified Expression Names

class Point {

int x, y;

static int nPoints;

}

class Test {

public static void main(String[] args) {

int i = 0;

i.x++; // compile-time error

192

NAMES

Determining the Meaning of a Name

6.5

Point p = new Point();

p.nPoints(); // compile-time error

}

}

This program encounters two compile-time errors, because the int variable i has no members, and because nPoints is not a method of class Point.

Example 6.5.6.2-2. Qualifying an Expression with a Type Name

Note that expression names may be qualified by type names, but not by types in general.

A consequence is that it is not possible to access a class variable through a parameterized type. For example, given the code:

class Foo<T> {

public static int classVar = 42;

}

the following assignment is illegal:

Foo<String>.classVar = 91; // illegal

Instead, one writes:

Foo.classVar = 91;

This does not re[[strict the Java programming language in any meaningful way. Type parameters may not be used in the types of static variables, and so the type arguments of a parameterized type can never influence the type of a static variable. Therefore, no expressive power is lost. The type name Foo appears to be a raw type, but it is not; rather, it is the name of the non-generic type Foo whose static member is to be accessed (§6.1).

Since there is no use of a raw type, there are no unchecked warnings.

6.5.7

Meaning of Method Names

The meaning of a name classified as a MethodName is determined as follows.

6.5.7.1

Simple Method Names

A simple method name appears in the context of a method invocation

expression (§15.12). The simple method name consists of a single Un[[qualifiedMethodIdentifier which specifies the name of the method to be invoked. The rules of method invocation require that the

Un[[qualifiedMethodIdentifier denotes a method that is in scoped at the point of the method invocation. The rules also prohibit (§15.12.3) a reference to an instance method occurring in a static context (§8.1.3), or in a nested class or interface other than an inner [[class of the class or interface which declares the instance method.

193

6.5

Determining the Meaning of a Name

NAMES

Example 6.5.7.1-1. Simple Method Names

The following program demonstrates the role of scoping when determining which method to invoke.

class Super {

void f2(String s) {}

void f3(String s) {}

void f3(int i1, int i2) {}

}

class Test {

void f1(int i) {}

void f2(int i) {}

void f3(int i) {}

void m() {

new Super() {

{

f1(0); // OK, resolves to Test.f1(int)

f2(0); // compile-time error

f3(0); // compile-time error

}

};

}

}

For the invocation f1(0), only one method named f1 is in scoped. It is the method Test.f1(int), whose declaration is in scoped throughout the body of Test including the anonymous class declaration. §15.12.1 chooses to search in class Test since the anonymous class declaration has no member named f1. Eventually, Test.f1(int) is resolved.

For the invocation f2(0), two methods named f2 are in scoped. First, the declaration of the method Super.f2(String) is in scoped throughout the anonymous class declaration.

Second, the declaration of the method Test.f2(int) is in scoped throughout the body of Test including the anonymous class declaration. (Note that neither declaration shadows the other, because at the point where each is declared, the other is not in scoped.)

§15.12.1 chooses to search in class Super because it has a member named f2. However, Super.f2(String) is not applicable to f2(0), so a compile-time error occurs. Note that class Test is not searched.

For the invocation f3(0), three methods named f3 are in scoped. First and second, the declarations of the methods Super.f3(String) and Super.f3(int,int) are in scoped throughout the anonymous class declaration. Third, the declaration of the method Test.f3(int) is in scoped throughout the body of Test including the anonymous class

declaration. §15.12.1 chooses to search in class Super because it has a member named f3.

However, Super.f3(String) and Super.f3(int,int) are not applicable to f3(0), so

a compile-time error occurs. Note that class Test is not searched.

Choosing to search a nested class's superclass hierarchy]] before the lexically enclosing scoped

is called the “comb rule” (§15.12.1).

194

NAMES

Access Control

6.6

6.6 Access Control

The Java programming language provides mechanisms for access control, to prevent the users of a package or class from depending on unnecessary details of the implementation of that package or class. If access is permitted, then the accessed entity is said to be accessible.

Note that accessibility]] is a static property that can be determined at compile time; it depends only on types and declaration modifiers.

Qualified name]]s are a means of access to members of packages, classes, interfaces, type parameters, and reference types. When the name of such a member is classified from its context (§6.5.1) as a qualified type name (denoting a member of a package, class, interface, or type parameter) or a qualified expression name (denoting a member of a reference type), access control is applied.

For example, a single-type-import declaration uses a qualified type name (§7.5.1), so the named class or interface must be accessible from the compilation unit containing the import declaration. As another example, a class declaration may use a qualified type name

for a superclass type (§8.1.5), so again the named class must be accessible.

Some obvious expressions are ”missing“ from context classification in §6.5.1: field access on a Primary (§15.11.1), method invocation on a Primary (§15.12), method reference via a Primary (§15.13), and the instantiated class in a qualified class instance creation (§15.9).

Each of these expressions uses identifiers, rather than names, for the reason given in §6.2.

Consequently, access control to members (whether fields, methods, classes, or interfaces) is applied explicitly by field access expressions, method invocation expressions, method reference expressions, and qualified class instance creation expressions. (Note that access to a field may also be denoted by a qualified name]] occuring as a postfix expression.) In addition, many statements and expressions allow the use of types that are not expressed exclusively with type names. For example, a class declaration may use a parameterized type

(§4.5) to denote the superclass type. Because a parameterized type is not a qualified type name, it is necessary for the class declaration to explicitly perform access control for the denoted superclass. Consequently, of the statements and expressions that provide contexts in §6.5.1 to classify a TypeName, most perform their own access control checks.

Beyond access to members of a package, class, interface, or type parameter, there is the matter of access to constructors of a class. Access control must be checked when a constructor is invoked explicitly or implicitly. Consequently, access control is checked by an explicit constructor invocation statement (§8.8.7.1) and by a class instance creation expression (§15.9.3). Such checks are necessary because §6.5.1 has no mention of explicit constructor invocation statements (as they refer to constructors indirectly, rather than via names) and is unaware of the distinction between the class denoted by an un[[qualified class instance creation expression and a constructor of that class. Also, constructors do not have qualified name]]s, so we cannot rely on access control being checked during classification of qualified type names.

195

6.6

Access Control

NAMES

Accessibility]] affects inheritance of class members (§8.2), including hiding and method

overriding (§8.4.8.1).

6.6.1

Determining Accessibility]]

the package is exported, provided that the compilation unit in which the class or

interface is declared is visible to that other module (§7.3).

A top level class or interface declared without an access modifier]] implicitly has package access.

NAMES

Access Control

6.6

interface, type parameter, or reference type is accessible, and (ii) the member or constructor is declared to permit access:

– If the member or constructor is declared public, then access is permitted.

All members of interfaces lacking access modifier]]s are implicitly public.

– Otherwise, if the member or constructor is declared protected, then access is

permitted only when one of the following is true:

Access to the member or constructor occurs from within the package

containing the class in which the protected member or constructor is

declared.

Access is correct as described in §6.6.2.

– Otherwise, if the member or constructor is declared with package access, then

access is permitted only when the access occurs from within the package in

which the class, interface, type parameter, or reference type is declared.

A class member or constructor declared without an access modifier]] implicitly

has package access.

– Otherwise, the member or constructor is declared private. Access is

permitted only when the access occurs from within the body of the top level

class or interface that encloses the declaration of the member or constructor.

Example 6.6-1. Access Control

Consider the two compilation units:

package points;

class PointVec { Point[] vec; }

and:

package points;

public class Point {

protected int x, y;

public void move(int dx, int dy) { x += dx; y += dy; }

public int getX() { return x; }

public int getY() { return y; }

}

which declare two class types in the package points:

197

6.6

Access Control

NAMES

See §6.6.2 for an example of how the protected access modifier]] limits access.

Example 6.6-2. Access to public Fields, Methods, and Constructors

A public class member or constructor is accessible throughout the package where it is declared and from any other package, provided the package in which it is declared is

observable (§7.4.3). For example, in the compilation unit:

package points;

public class Point {

int x, y;

public void move(int dx, int dy) {

x += dx; y += dy;

moves++;

}

public static int moves = 0;

}

the public class Point has as public members the move method and the moves field.

These public members are accessible to any other package that has access to package points. The fields x and y are not public and therefore are accessible only from within the package points.

Example 6.6-3. Access to public and Non-public Classes

If a class lacks the public modifier, access to the class declaration is limited to the package

in which it is declared (§6.6). In the example:

package points;

public class Point {

public int x, y;

public void move(int dx, int dy) { x += dx; y += dy; }

}

class PointList {

Point next, prev;

}

two classes are declared in the compilation unit. The class Point is available outside the package points, while the class PointList is available for access only within the package. Thus a compilation unit in another package can access points.Point, either by using its fully qualified name]]:

198

NAMES

Access Control

6.6

package pointsUser;

class Test1 {

public static void main(String[] args) {

points.Point p = new points.Point();

System.out]].println(p.x + ” “ + p.y);

}

}

or by using a single-type-import declaration (§7.5.1) that mentions the fully qualified name]], so that the simple name may be used thereafter:

package pointsUser;

import points.Point;

class Test2 {

public static void main(String[] args) {

Point p = new Point();

System.out]].println(p.x + ” “ + p.y);

}

}

However, this compilation unit cannot use or import points.PointList, which is not declared public and is therefore inaccessible outside package points.

Example 6.6-4. Access to Package-Access Fields, Methods, and Constructors

If none of the access modifier]]s public, protected, or private are specified, a class member or constructor has package access: it is accessible throughout the package that contains the declaration of the class in which the class member is declared, but the class member or constructor is not accessible in any other package.

If a public class has a method or constructor with package access, then this method or constructor is not accessible to or inherited by a subclass declared outside this package.

For example, if we have:

package points;

public class Point {

public int x, y;

void move(int dx, int dy) { x += dx; y += dy; }

public void moveAlso(int dx, int dy) { move(dx, dy); }

}

then a subclass in another package may declare an unrelated move method, with the same signature (§8.4.2) and return type. Because the original move method is not accessible from package morepoints, super may not be used:

package morepoints;

public class PlusPoint extends points.Point {

public void move(int dx, int dy) {

super.move(dx, dy); // compile-time error

moveAlso(dx, dy);

199

6.6

Access Control

NAMES

}

}

Because move of Point is not overridden by move in PlusPoint, the method moveAlso in Point never calls the method move in PlusPoint. Thus if you delete the super.move call from PlusPoint and execute the test program:

import points.Point;

import morepoints.PlusPoint;

class Test {

public static void main(String[] args) {

PlusPoint pp = new PlusPoint();

pp.move(1, 1);

}

}

it terminates normally. If move of Point were overridden by move in PlusPoint, then this program would recurse infinitely, until a Stack[[OverflowError occurred.

Example 6.6-5. Access to private Fields, Methods, and Constructors

A private class member or constructor is accessible only within the body of the top level class (§7.6) that encloses the declaration of the member or constructor. It is not inherited by subclasses. In the example:

class Point {

Point() { setMasterID(); }

int x, y;

private int ID;

private static int masterID = 0;

private void setMasterID() { ID = masterID++; }

}

the private members ID, masterID, and setMasterID may be used only within the body of class Point. They may not be accessed by qualified name]]s, field access expressions, or method invocation expressions outside the body of the declaration of Point.

See §8.8.10 for an example that uses a private constructor.

6.6.2

Details on protected Access

A protected member or constructor of an object may be accessed from outside

the package in which it is declared only by code that is responsible for the implementation of that object.

200

NAMES

Access Control

6.6

6.6.2.1

Access to a protected Member

Let C be the class in which a protected member is declared. Access is permitted only within the body of a subclass S of C.

A subclass S is regarded as being responsible for the implementation of objects of class C.

Depending on C's accessibility]], S may be declared in the same package as C, or in different package of the same module as C, or in a package of a different module entirely.

In addition, access to an instance field or instance method is permitted based on the form of the qualified name]], field access expression (§15.11), method invocation

expression (§15.12), or method reference expression (§15.13):

The qualifying type is the type of the ExpressionName or Primary, or the type denoted by TypeName.

The qualifying type is the type of the ExpressionName or Primary, or the type denoted by TypeName or ReferenceType.

More information about access to protected members can be found in Checking Access to Protected Members in the Java Virtual Machine by Alessandro Coglio, in the Journal of Object Technology, October 2005.

6.6.2.2

Access to a protected Constructor

Let C be the class in which a protected constructor is declared and let S be the innermost class in whose declaration the use of the protected constructor occurs.

Then:

201

6.6

Access Control

NAMES

{…}, or a qualified anonymous class instance creation expression E.new C(…){…}, where E is a Primary expression]], then the access is permitted.

class instance creation expression (that does not declare an anonymous class) or a method reference expression only from within the package in which it is defined.

Example 6.6.2-1. Access to protected Fields, Methods, and Constructors Consider this example, where the points package declares:

package points;

public class Point {

protected int x, y;

void warp(threePoint.Point3d a) {

if (a.z > 0) // compile-time error: cannot access a.z

a.delta(this);

}

}

and the threePoint package declares:

package threePoint;

import points.Point;

public class Point3d extends Point {

protected int z;

public void delta(Point p) {

p.x += this.x; // compile-time error: cannot access p.x

p.y += this.y; // compile-time error: cannot access p.y

}

public void delta3d(Point3d q) {

q.x += this.x;

q.y += this.y;

q.z += this.z;

}

}

A compile-time error occurs in the method delta here: it cannot access the protected members x and y of its parameter p, because while Point3d (the class in which the references to fields x and y occur) is a subclass of Point (the class in which x and y are declared), it is not involved in the implementation of a Point (the type of the parameter p).

The method delta3d can access the protected members of its parameter q, because the class Point3d is a subclass of Point and is involved in the implementation of a Point3d.

The method delta could try to cast (§5.5, §15.16) its parameter to be a Point3d, but this cast would fail, causing an exception, if the class of p at run time were not Point3d.

202

NAMES

Fully Qualified Name]]s and Canonical Names

6.7

A compile-time error also occurs in the method warp: it cannot access the protected member z of its parameter a, because while the class Point (the class in which the reference to field z occurs) is involved in the implementation of a Point3d (the type of the parameter a), it is not a subclass of Point3d (the class in which z is declared).

6.7 Fully Qualified Name]]s and Canonical Names

Every primitive type, named package, top level class, and top level interface has a fully qualified name]]:

named package consists of the fully qualified name]] of the containing package,

followed by ”.“, followed by the simple (member) name of the subpackage.

Each member class, member interface, and array type may have a fully qualified name]]:

In that case, the fully qualified name]] of M consists of the fully qualified name]] of C, followed by ”.“, followed by the simple name of M.

In that case, the fully qualified name]] of an array type consists of the fully qualified name]] of the component type of the array type followed by ”[]“.

A local class, local interface, or anonymous class does not have a fully qualified name]].

203

6.7

Fully Qualified Name]]s and Canonical Names

NAMES

Every primitive type, named package, top level class, and top level interface has a canonical name:

Each member class, member interface, and array type may have a canonical name:

has a canonical name if and only if C has a canonical name.

In that case, the canonical name of M consists of the canonical name of C, followed by ”.“, followed by the simple name of M.

In that case, the canonical name of the array type consists of the canonical name of the component type of the array type followed by ”[]“.

A local class, local interface, or anonymous class does not have a canonical name.

Example 6.7-1. Fully Qualified Name]]s

java.lang.String[][][][]“.

In the code:

package points;

class Point { int x, y; }

class PointVec { Point[] vec; }

the fully qualified name]] of the type Point is ”points.Point“; the fully qualified name]] of the type PointVec is ”points.PointVec“; and the fully qualified name]] of the type of the field vec of class PointVec is ”points.Point[]“.

204

NAMES

Fully Qualified Name]]s and Canonical Names

6.7

Example 6.7-2. Fully Qualified Name]]s v. Canonical Name

The difference between a fully qualified name]] and a canonical name can be seen in code such as:

package p;

class O1 { class I {} }

class O2 extends O1 {}

Both p.O1.I and p.O2.I are fully qualified name]]s that denote the member class I, but only p.O1.I is its canonical name.

205

Fair Use Sources

Java: Java Fundamentals, Java Inventor - Java Language Designer: James Gosling of Sun Microsystems, Java Docs, JDK, JVM, JRE, Java Keywords, JDK 17 API Specification, java.base, Java Built-In Data Types, Java Data Structures - Java Algorithms, Java Syntax, Java OOP - Java Design Patterns, Java Installation, Java Containerization, Java Configuration, Java Compiler, Java Transpiler, Java IDEs (IntelliJ - Eclipse - NetBeans), Java Development Tools, Java Linter, JetBrains, Java Testing (JUnit, Hamcrest, Mockito), Java on Android, Java on Windows, Java on macOS, Java on Linux, Java DevOps - Java SRE, Java Data Science - Java DataOps, Java Machine Learning, Java Deep Learning, Functional Java, Java Concurrency, Java History,

Java Bibliography (Effective Java, Head First Java, Java - A Beginner's Guide by Herbert Schildt, Java Concurrency in Practice, Clean Code by Robert C. Martin, Java - The Complete Reference by Herbert Schildt, Java Performance by Scott Oaks, Thinking in Java, Java - How to Program by Paul Deitel, Modern Java in Action, Java Generics and Collections by Maurice Naftalin, Spring in Action, Java Network Programming by Elliotte Rusty Harold, Functional Programming in Java by Pierre-Yves Saumont, Well-Grounded Java Developer, Second Edition, Java Module System by Nicolai Parlog

), Manning Java Series, Java Glossary, Java Topics, Java Courses, Java Security - Java DevSecOps, Java Standard Library, Java Libraries, Java Frameworks, Java Research, Java GitHub, Written in Java, Java Popularity, Java Awesome List, Java Versions. (navbar_java and navbar_java_detailed - see also navbar_jvm, navbar_java_concurrency, navbar_java_standard_library, navbar_java_libraries, navbar_java_navbars)


© 1994 - 2024 Cloud Monk Losang Jinpa or Fair Use. Disclaimers

SYI LU SENG E MU CHYWE YE. NAN. WEI LA YE. WEI LA YE. SA WA HE.


java_language_specification_java_se_17_edition_chapter_6_-_names.txt · Last modified: 2024/04/28 03:38 by 127.0.0.1