Static Members in Classes
Static members belong to the class in which they are declared and are not part of any instance of the class. The declaration of static members is prefixed by the keyword static to distinguish them from instance members.
Static code inside a class can access a static member in the following three ways:
- By the static member’s simple name
- By using the class name with the static member’s name
- By using an object reference of the static member’s class with the static member’s name
Depending on the access modifier of the static members declared in a class, clients can only access these members by using the class name or using an object reference of their class.
The class need not be instantiated to access its static members. This is in contrast to instance members of the class which can only be accessed by references that actually refer to an instance of the class.
Static Fields in Classes
Static fields (also called static variables and class variables) exist only in the class in which they are defined. When the class is loaded, static fields are initialized to their default values if no explicit initialization is specified. They are not created when an instance of the class is created. In other words, the values of these fields are not a part of the state of any object. Static fields are akin to global variables that can be shared with all objects of the class and with other clients, if necessary.
Example 3.6 Accessing Static Members in a Class
// File: StaticTest.java
import static java.lang.System.out;
class Light {
// Static field:
static int counter; // (1) No initializer expression
// Static method:
public static void printStatic() {
Light myLight = null;
out.printf(“%s, %s, %s%n”, counter, Light.counter, myLight.counter); // (2)
long counter = 10; // (3) Local variable shadows static field
out.println(“Local counter: ” + counter); // (4) Local variable accessed
out.println(“Static counter: ” + Light.counter);// (5) Static field accessed
// out.println(this.counter); // (6) Cannot use this in static context
// printNonStatic(); // (7) Cannot call non-static method
}
// Non-static method:
public void printNonStatic() {
out.printf(“%s, %s, %s%n”, counter, this.counter, Light.counter); // (8)
}
}
//______________________________________________________________________________
public class StaticTest { // Client of class Light
public static void main(String[] args) {
Light.counter++; // (9) Using class name
Light dimLight = null;
dimLight.counter++; // (10) Using object reference
out.print(“Light.counter == dimLight.counter: “);
out.println(Light.counter == dimLight.counter);//(11) Aliases for static field
out.println(“Calling static method using class name:”);
Light.printStatic(); // (12) Using class name
out.println(“Calling static method using object reference:”);
dimLight.printStatic(); // (13) Using object reference
}
}
Output from the program:
Light.counter == dimLight.counter: true
Calling static method using class name:
2, 2, 2
Local counter: 10
Static counter: 2
Calling static method using object reference:
2, 2, 2
Local counter: 10
Static counter: 2
In Example 3.6, the static field counter at (1) will be initialized to the default value 0 when the class is loaded at runtime, since no initializer expression is specified. The print statement at (2) in the static method printCount() shows how this static field can be accessed in three different ways, respectively: simple name counter, the class name Light, and object reference myLight of class Light, although no object has been created.
Shadowing of fields by local variables is different from hiding of fields by field declarations in subclasses. In Example 3.6, a local variable is declared at (3) that has the same name as the static field. Since this local variable shadows the static field, the simple name at (4) now refers to the local variable, as shown by the output from the program. The shadowed static field can of course be accessed using the class name, as shown at (5). It is the local variable that is accessed by its simple name as long as it is in scope.
Trying to access the static field with the this reference at (6) results in a compile-time error, since the this reference cannot be used in static code. Invoking the non-static method at (7) also results in a compile-time error, since static code cannot refer to non-static members by its simple name in the class.
The print statement at (8) in the method printNonStatic() illustrates referring to static members in non-static code: It refers to the static field counter by its simple name, with the this reference, and using the class name.
In Example 3.6, the class StaticTest is a client of the class Light. The client must use the class name or an object reference of class Light at (9) and (10), respectively, to access the static field counter in the class Light. The result from the print statement at (11) shows that these two ways of accessing a static field are equivalent.