The data fields radius and numberOfObjects in the Circle2 class in Listing 7.2 can be modified directly (e.g., myCircle.radius = 5 or Circle2.numberOfObjects = 10 ). This is not a good practice for two reasons:
First, data may be tampered. For example, numberOfObjects is to count the number of objects created, but it may be set to an arbitrary value (e.g., Circle2. numberOfObjects = 10 ).
Second, it makes the class difficult to maintain and vulnerable to bugs . Suppose you want to modify the Circle2 class to ensure that the radius is non-negative after other programs have already used the class. You have to change not only the Circle2 class, but also the programs that use the Circle2 class. Such programs are often referred to as clients . This is because the clients may have modified the radius directly (e.g., myCircle.radius = -5 ).
To prevent direct modifications of properties, you should declare the field private, using the private modifier. This is known as data field encapsulation .
A private data field cannot be accessed by an object through a direct reference outside the class that defines the private field. But often a client needs to retrieve and modify a data field. To make a private data field accessible, provide a get method to return the value of the data field. To enable a private data field to be updated, provide a set method to set a new value.
Note
Colloquially, a get method is referred to as a getter (or accessor ), and a set method is referred to as a setter (or mutator ). |
A get method has the following signature:
public returnType get PropertyName ()
If the returnType is boolean , the get method should be defined as follows by convention:
public boolean is PropertyName ()
A set method has the following signature:
public void set PropertyName(dataType propertyValue )
Let us create a new circle class with a private data field radius and its associated accessor and mutator methods . The class diagram is shown in Figure 7.15. The new circle class, named Circle3 , is declared in Listing 7.5.
1 public class Circle3 { 2 /** The radius of the circle */ 3 private double radius = 1 ; 4 5 /** The number of the objects created */ 6 private static int numberOfObjects = ; 7 8 /** Construct a circle with radius 1 */ 9 public Circle3() { 10 numberOfObjects++; 11 } 12 13 /** Construct a circle with a specified radius */ 14 public Circle3( double newRadius) { 15 radius = newRadius; 16 numberOfObjects++; 17 } 18 19 /** Return radius */ 20 public double getRadius() { 21 return radius; 22 } 23 24 /** Set a new radius */ 25 public void setRadius( double newRadius) { 26 radius = (newRadius >= ) ? newRadius : ; 27 } 28 29 /** Return numberOfObjects */ 30 public static int getNumberOfObjects() { 31 return numberOfObjects; 32 } 33 34 /** Return the area of this circle */ 35 public double getArea() { 36 return radius * radius * Math.PI; 37 } 38 } |
The getRadius() method (lines 20 “22) returns the radius, and the setRadius(newRadius) method (lines 25 “27) sets a new radius into the object. If the new radius is negative, is set to the radius in the object. Since these methods are the only ways to read and modify radius, you have total control over how the radius property is accessed. If you have to change the implementation of these methods, you need not change the client programs. This makes the class easy to maintain.
Here is a client program that uses the Circle3 class to create a Circle3 object and modifies the radius using the setRadius method.
1 // TestCircle3.java: Demonstrate private modifier 2 public class TestCircle3 { 3 /** Main method */ 4 public static void main(String[] args) { 5 // Create a Circle with radius 5.0 6 Circle myCircle = new Circle( 5.0 ); 7 System.out.println( "The area of the circle of radius " 8 + myCircle.getRadius() + " is " + myCircle.getArea() ); 9 10 // Increase myCircle's radius by 10% 11 myCircle.setRadius(myCircle.getRadius() * 1.1 ); 12 System.out.println( "The area of the circle of radius " 13 + myCircle.getRadius() + " is " + myCircle.getArea() ); 14 } 15 }
The data field radius is declared private. Private data can only be accessed within their defining class. You cannot use myCircle.radius in the client program. A compilation error would occur if you attempted to access private data from a client.
Since numberOfObjects is private, it cannot be modified. This prevents tampering. For example, the user cannot set numberOfObjects to 100 . The only way to make it 100 is to create one hundred objects of the Circle3 class.
Suppose you combined TestCircle3 and Circle3 into one class by moving the main method in TestCircle3 into Circle3 . Could you use myCircle.radius in the main method? See Review Question 7.15 for the answer.
Note
When you compile TestCircle3.java , the Java compiler automatically compiles Circle3.java if it has not been compiled since the last change. |
Tip
To prevent data from being tampered with and to make the class easy to maintain, most of the data fields in this book will be private. |