The data field radius in the circle class in Listing 7.1 is known as an instance variable . An instance variable is tied to a specific instance of the class; it is not shared among objects of the same class. For example, suppose that you create the following objects:
Circle circle1 = new Circle(); Circle circle2 = new Circle( 5 );
The radius in circle1 is independent of the radius in circle2 , and is stored in a different memory location. Changes made to circle1 's radius do not affect circle2 's radius , and vice versa.
If you want all the instances of a class to share data, use static variables . Static variables store values for the variables in a common memory location. Because of this common location, all objects of the same class are affected if one object changes the value of a static variable. Java supports static methods as well as static variables. Static methods can be called without creating an instance of the class.
Let us modify the Circle class by adding a static variable numberOfObjects to count the number of circle objects created. When the first object of this class is created, numberOfObjects is 1 . When the second object is created, numberOfObjects becomes 2 . The UML of the new circle class is shown in Figure 7.10. The Circle class defines the instance variable radius and the static variable numberOfObjects , the instance methods getRadius , setRadius , and getArea , and the static method getNumberOfObjects . (Note that static variables and functions are underlined in the UML class diagram.)
To declare a static variable or a static method, put the modifier static in the variable or method declaration. The static variable numberOfObjects and the static method getNumberOfObjects() can be declared as follows :
[Page 225] static int numberOfObjects; static int getNumberObjects() { return numberOfObjects; }
Constants in a class are shared by all objects of the class. Thus, constants should be declared final static . For example, the constant PI in the Math class is defined as:
final static double PI = 3.14159265358979323846 ;
The new circle class, named Circle2 , is declared in Listing 7.3.
1 public class Circle2 { 2 /** The radius of the circle */ 3 double radius; 4 5 /** The number of the objects created */ 6 static int numberOfObjects = ; 7 8 /** Construct a circle with radius 1 */ 9 Circle2() { 10 radius = 1 . ; 11 numberOfObjects++; 12 } 13 14 /** Construct a circle with a specified radius */ 15 Circle2( double newRadius) { 16 radius = newRadius; 17 numberOfObjects++; 18 } 19 20 /** Return numberOfObjects */ 21 static int getNumberOfObjects() { 22 return numberOfObjects; 23 } 24 25 /** Return the area of this circle */ 26 double getArea() { 27 return radius * radius * Math.PI; 28 } 29 } |
Method getNumberOfObjects() in Circle2 is a static method. Other examples of static methods are showMessageDialog and showInputDialog in the JOptionPane class, and all the methods in the Math class. In fact, so are all the methods used in Part 1 of this book, including the main method.
Instance methods (e.g., getArea() ) and instance data (e.g., radius ) belong to instances and can only be used after the instances are created. They are accessed via a reference variable. Static methods (e.g., getNumberOfObjects() ) and static data (e.g., numberOfObjects ) can be accessed from a reference variable or from their class name .
The program in Listing 7.4 demonstrates how to use instance and static variables and methods, and illustrates the effects of using them. Its output is shown in Figure 7.11.
1 public class TestCircle2 { 2 /** Main method */ 3 public static void main(String[] args) { 4 // Create c1 5 Circle2 c1 = new Circle2(); 6 7 // Display c1 BEFORE c2 is created 8 System.out.println( "Before creating c2" ); 9 System.out.println( "c1 is : radius (" + c1.radius + 10 ") and number of Circle objects (" + 11 c1.numberOfObjects + ")" ); 12 13 // Create c2 14 Circle2 c2 = new Circle2( 5 ); 15 16 // Change the radius in c1 17 c1.radius = 9 ; 18 19 // Display c1 and c2 AFTER c2 was created 20 System.out.println( "\nAfter creating c2 and modifying " + 21 "c1's radius to 9" ); 22 System.out.println( "c1 is : radius (" + c1.radius + 23 ") and number of Circle objects (" + 24 c1.numberOfObjects + ")" ); 25 System.out.println( "c2 is : radius (" + c2.radius + 26 ") and number of Circle objects (" + 27 c2.numberOfObjects + ")" ); 28 } 29 } |
The main method creates two circles, c1 and c2 (lines 5, 14). The instance variable radius in c1 is modified to become 9 (line 17). This change does not affect the instance variable radius in c2 , since these two instance variables are independent. The static variable numberOfObjects becomes 1 after c1 is created (line 5), and it becomes 2 after c2 is created (line 14).
Note that PI is a constant defined in Math and Math.PI access the constant. c1.numberOfObjects and c2.numberOfObjects could be replaced by Circle2.numberOfObjects . This improves readability. You can also replace Circle2.numberOfObjects by Circle2.getNumberOfObjects() .
Tip
Use ClassName.methodName(arguments) to invoke a static method and ClassName.staticVariable . This improves readability because the user can easily recognize the static method and data in the class. |
Note
You can use a new JDK 1.5 feature to directly import static variables and methods from a class. The imported data and methods can be referenced or called without specifying a class. For example, you can use PI (instead of Math.PI ), and random() (instead of Math.random() ), if you have the following import statement in the class: import static java.lang.Math.*; |
Caution
Static variables and methods can be used from instance or static methods in the class. However, instance variables and methods can only be used from instance methods, not from static methods, since static variables and methods belong to the class as a whole and not to particular objects. Thus the code given below would be wrong. |
public class Foo { int i = 5 ; static int k = 2 ; public static void main(String[] args) { int j = i; // Wrong because i is an instance variable m1(); // Wrong because m1() is an instance method } public void m1() { // Correct since instance and static variables and methods // can be used in an instance method i = i + k + m2(i, k); } public static int m2( int i, int j) { return ( int )(Math.pow(i, j)); } }
Tip
How do you decide whether a variable or method should be an instance one or a static one? A variable or method that is dependent on a specific instance of the class should be an instance variable or method. A variable or method that is not dependent on a specific instance of the class should be a static variable or method. For example, every circle has its own radius. Radius is dependent on a specific circle. Therefore, radius is an instance variable of the Circle class. Since the getArea method is dependent on a specific circle, it is an instance method. None of the methods in the Math class, such as random , pow , sin , and cos , is dependent on a specific instance. Therefore, these methods are static methods. The main method is static, and can be invoked directly from a class. |
Caution
It is a common design error to declare an instance method that should have been declared static. For example, the following method factorial(int n) should be declared static, because it is independent of any specific instance. |