A name refers to something declared in the program: a module, package, class, interface, type parameter, member, parameter, local variable or label. This page covers where each declaration can be used by its simple name, what happens when names clash, and who may use a name at all (JLS chapter 6).
Declarations and names
A simple name is one identifier, such as count; a
qualified name is a name, a dot and an identifier, such as
java.util.List or System.out. Things that can be declared
(JLS 6.1):
- modules, in
module-info.java, and packages; - imported types and static members, in a compilation unit;
- top-level, member and local classes and interfaces, including enum, record and annotation interfaces;
- type parameters of classes, interfaces, methods and constructors;
- fields, methods, enum constants and record components;
- parameters of methods, constructors, lambdas and catch clauses;
- local variables, including those declared in
forheaders, resources and pattern variables; - statement labels.
Fields, methods, types and packages live in different namespaces, so a class
may have a field, a method and a nested class all called value. The
context decides which is meant (JLS 6.5).
Scope
The scope of a declaration is the part of the program where it can be referred to by its simple name (JLS 6.3):
| Declaration | Scope |
|---|---|
| Top-level class or interface | Every compilation unit of its package |
| Imported type or static member | The compilation unit holding the import |
| Member (field, method, nested type) | The whole body of the class, including code written before the declaration (but see forward references) |
| Enum constant, record component | The whole body of the enum or record |
| Type parameter of a class | The type parameter section, superclass, superinterfaces and body |
| Type parameter of a method | The whole method declaration, including its other type parameters and its throws clause |
| Method, constructor or lambda parameter | The body |
| Local variable in a block | From its own declarator, including its initialiser, to the end of the block |
Variable declared in a for header | The rest of the header and the body |
Exception parameter of catch | The catch block |
| Resource in try-with-resources | The rest of the resource list and the try block |
| Pattern variable | Wherever the pattern has definitely matched: see flow scoping |
| Local class or interface | The rest of the enclosing block, including its own declaration |
| Label | The labelled statement |
Forward references in initialisers
A field can be used anywhere in its class, but its initialiser runs in textual order, so a field may not be read by its simple name in an initialiser written before its own declaration (JLS 8.3.3). Methods called from initialisers have no such check and can see default values.
class Order {
int a = b + 1; // error: illegal forward reference
int c = this.b + 1; // compiles: c is 1, because b is still 0
int b = 2;
int d = next(); // compiles: next() reads e, which is still 0
int e = 5;
int next() { return e; }
}
Shadowing, obscuring and hiding
Shadowing
A declaration shadows another of the same name whose scope it is inside
(JLS 6.4.1). A local variable or parameter shadows a field; a nested class’s member
shadows a member of the enclosing class; a single-type import shadows a type of the
same name in the same package. The shadowed field can still be reached through
this or the class name:
class Point {
int x;
Point(int x) { this.x = x; } // the parameter x shadows the field x
}
Local variables cannot shadow each other: it is an error to declare a local variable, parameter or pattern variable with the name of another one whose scope it is in, within the same method, constructor, initialiser or lambda. A lambda’s parameters cannot reuse the names of local variables of the enclosing method. A local or anonymous class may shadow its enclosing method’s variables.
Obscuring
Where a simple name could mean a variable, a type or a package, a variable wins over
a type and a type over a package (JLS 6.4.2). A local variable called
System would make System.out mean its field
out. Naming conventions keep this rare.
Hiding, overriding and overloading
| Situation | Name | Effect |
|---|---|---|
| An instance method with the same signature as an inherited one | Overriding | The call is chosen by the object’s class at run time |
| A static method with the same signature as an inherited static one | Hiding | The call is chosen by the type at compile time |
| A field with the same name as an inherited field | Hiding | Both fields exist; super.f reaches the old one |
| A nested type with the same name as an inherited one | Hiding | The inherited one needs a qualified name |
| Methods with the same name but different parameter types | Overloading | The compiler picks one from the argument types |
A static method cannot hide an instance method, and an instance method cannot override a static one. Fields are never overridden, only hidden.
How a name is resolved
The compiler first classifies a name by where it appears (JLS 6.5): as a module name
(in module directives), a package name, a type name, an expression name (a variable),
a method name, or, where it cannot yet tell, a package-or-type name or an
ambiguous name. An ambiguous name such as a.b.c is resolved from
the left: a is tried as a variable, then a type, then a package, and each
following identifier is looked up inside what was found.
Access control
Access modifiers decide which code may use a member or type by name (JLS 6.6). Access is checked at compile time and again when the class is linked.
| Modifier | Same class | Same package | Subclass in another package | Anywhere |
|---|---|---|---|---|
public | yes | yes | yes | yes |
protected | yes | yes | yes, through its own type | no |
| none (package access) | yes | yes | no | no |
private | yes, and within the whole top-level class | no | no | no |
- Top-level classes and interfaces can only be
publicor have package access. Member types can use all four. privateis per top-level class, not per object or per nested class: a nested class and its enclosing class may use each other’s private members, and an object may read another object’s private fields of the same class.- A
protectedinstance member used from a subclass in another package must be reached through a reference of that subclass’s type (or a subtype of it), not through the superclass type: inclass B extends A,this.pandotherB.pare fine,someA.pis not. - Interface members are implicitly
public, exceptprivatemethods (Java 9). - With modules (Java 9), a
publictype is accessible outside its module only if its package is exported to the module using it; see Packages and modules.
Fully qualified and canonical names
Every package, top-level type and member type has a fully qualified name:
java.lang, java.lang.String,
java.util.Map.Entry. The canonical name is the one fully
qualified name with no alias: if class B extends A and A
declares member class M, then p.B.M is a fully qualified name
but only p.A.M is canonical (JLS 6.7). The canonical name of an array type
is its component’s with []: java.lang.String[]. Local and
anonymous classes have neither.
The binary name, used in class files and by Class.getName(),
separates nested types with $: java.util.Map$Entry.
Naming conventions
Not enforced by the compiler, but followed by the platform and almost all code (JLS 6.1):
| Kind | Style | Example |
|---|---|---|
| Package, module | Lower case, reversed domain first | com.example.shapes |
| Class, interface, enum, record | Upper camel case, nouns | ArrayList, Runnable |
| Type parameter | One capital letter | T, E, K, V |
| Method | Lower camel case, verbs | toString, isEmpty |
| Field, variable, parameter | Lower camel case | lineCount |
| Constant | Upper case with underscores | MAX_VALUE |