Java provides explicit accessibility modifiers to control the accessibility of members in a class by external clients (see Section 4.9, p. 137), but in two areas access is governed by specific scope rules:
Class scope for members: how member declarations are accessed within the class.
Block scope for local variables: how local variable declarations are accessed within a block.
Class scope concerns accessing members (including inherited ones) from code within a class. Table 4.1 gives an overview of how static and non-static code in a class can access members of the class, including those that are inherited. Table 4.1 assumes the following declarations:
class SuperName { int instanceVarInSuper; static int staticVarInSuper; void instanceMethodInSuper() { /* ... */ } static void staticMethodInSuper() { /* ... */ } // ... } class ClassName extends SuperName { int instanceVar; static int staticVar; void instanceMethod() { /* ... */ } static void staticMethod() { /* ... */ } // ... }
The golden rule is that static code cannot access non-static members by their simple names. Static code is not executed in the context of an object, therefore the references this and super are not available. An object has knowledge of its class, therefore, static members are always accessible in a non-static context.
Note that using the class name to access static members within the class is no different from how external clients access these static members.
Some factors that can influence the scope of a member declaration are
shadowing of a field declaration, either by local variables (see Section 4.3, p. 114) or by declarations in the subclass (see Section 6.2, p. 233)
initializers preceding the field declaration (see Section 8.2, p. 331)
overriding an instance method from a superclass (see Section 6.2, p. 233)
hiding a static method declared in a superclass (see Section 6.2, p. 233)
Accessing members within nested classes is discussed in Chapter 7.
Member declarations | Non-static Code in the Class ClassName Can Refer to the Member as | Static Code in the Class ClassName Can Refer to the Member as |
---|---|---|
Instance variables |
instanceVar this.instanceVar instanceVarInSuper this.instanceVarInSuper super.instanceVarInSuper | Not possible |
Instance methods |
instanceMethod() this.instanceMethod() instanceMethodInSuper() this.instanceMethodInSuper() super.instanceMethodInSuper() | Not possible |
Static variables |
staticVar this.staticVar ClassName.staticVar staticVarInSuper this.staticVarInSuper super.staticVarInSuper ClassName.staticVarInSuper SuperName.staticVarInSuper |
staticVar ClassName.staticVar staticVarInSuper ClassName.staticVarInSuper SuperName.staticVarInSuper |
Static methods |
staticMethod() this.staticMethod() ClassName.staticMethod() staticMethodInSuper() this.staticMethodInSuper() super.staticMethodInSuper() ClassName.staticMethodInSuper() SuperName.staticMethodInSuper() |
staticMethod() ClassName.staticMethod() staticMethodInSuper() ClassName.staticMethodInSuper() SuperName.staticMethodInSuper() |
Within a class C, reference variables of type C can be used to access all members in the class C, regardless of their accessibility modifiers. In Example 4.6, the method duplicateLight at (1) in class Light has a parameter oldLight and a local variable newLight that are references to Light objects. Even though the fields of the class are private, they are accessible through the two references (oldLight and newLight) in the method duplicateLight() as shown at (2), (3), and (4).
class Light { // Instance variables private int noOfWatts; // wattage private boolean indicator; // on or off private String location; // placement // Instance methods public void switchOn() { indicator = true; } public void switchOff() { indicator = false; } public boolean isOn() { return indicator; } public static Light duplicateLight(Light oldLight) { // (1) Light newLight = new Light(); newLight.noOfWatts = oldLight.noOfWatts; // (2) newLight.indicator = oldLight.indicator; // (3) newLight.location = oldLight.location; // (4) return newLight; } }
Declarations and statements can be grouped into a block using braces, {}. Blocks can be nested, and certain scope rules apply to local variable declarations in such blocks. A local declaration can appear anywhere in a block. The general rule is that a variable declared in a block is in scope inside the block in which it is declared, but it is not accessible outside of this block. It is not possible to redeclare a variable if a local variable of the same name is already declared in the current scope.
Local variables of a method are comprised of formal parameters of the method and variables that are declared in the method body. The local variables in a method are distinct for each invocation, and have their own storage.
A method body is a block. Parameters cannot be redeclared in the method body, as shown at (1) in Block 1 (see Figure 4.2).
A local variable?already declared in an enclosing block and, therefore, visible in a nested block?cannot be redeclared in the nested block. These cases are shown at (3), (5), and (6).
A local variable in a block can be redeclared in another block if the blocks are disjoint, that is, they do not overlap. This is the case for variable i at (2) in Block 3 and at (4) in Block 4, as these two blocks are disjoint.
The scope of a declaration begins from where it is declared in the block and ends where this block terminates. The scope of the loop variable index is Block 2. Even though Block 2 is nested in Block 1, the declaration of the variable index at (7) in Block 1 is valid. Its scope spans from its declaration to the end of this block, and it does not overlap with that of the loop variable index in Block 2.