Previous | Table of Contents | Next |
14.3.8.2. Data Access Methods
In the Circle example weve been using, weve declared the circle position and radius to be public fields. In fact, the Circle class is one where it may well make sense to keep those visibleit is a simple enough class, with no dependencies between the variables.
On the other hand, suppose we wanted to impose a maximum radius on objects of the Circle class. Then it would be better to hide the r variable so that it could not be set directly. Instead of a visible r variable, wed implement a setRadius() method that verifies that the specified radius isnt too large and then sets the r variable internally. Example 14.20 shows how we might implement Circle with encapsulated data and a restriction on radius size. For convenience, we use protected fields for the radius and position variables. This means that subclasses of Circle, or cooperating classes within the shapes package are able to access these variables directly. To any other classes, however, the variables are hidden. Also, note the private constant and method used to check whether a specified radius is legal. And finally, notice the public methods that allow you to set and query the values of the instance variables.
EXAMPLE 14.20. Hiding variables in the Circle class.
package shapes; // Specify a package for the class. public class Circle { // Note that the class is still public! protected double x, y; // Position is hidden, but visible to subclasses. protected double r; // Radius is hidden, but visible to subclasses. private static final double MAXR = 100.0; // Maximum radius (constant). private boolean check_radius(double r) { return (r <= MAXR); } // Public constructors public Circle(double x, double y, double r) { this.x = x; this.y = y; if (check_radius(r)) this.r = r; else this.r = MAXR; } public Circle(double r) { this(0.0, 0.0, r); } public Circle() { this(0.0, 0.0, 1.0); } // Public data access methods public void moveto(double x, double y) { this.x = x; this.y = y;} public void move(double dx, double dy) { x += dx; y += dy; } public void setRadius(double r) { this.r = (check_radius(r))?r:MAXR; } // Declare these trivial methods final so we dont get dynamic // method lookup and so that they can be inlined by the compiler. public final double getX() { return x; }; public final double getY() { return y; }; public final double getRadius() { return r; }; }
In Example 14.20, we declared our Circle class to be part of a package named shapes. Suppose we plan to implement a number of shape classes: Rectangle, Square, Ellipse, Triangle, and so on. Well give all of these shape classes our two basic area() and circumference() methods. Now, to make it easy to work with an array of shapes, it would be helpful if all our shape classes have a common superclass, Shape. We want Shape to encapsulate whatever features all our shapes have in common. In this case, what they have in common is the area() and circumference() methods. But our generic Shape class cant actually implement these methods, since it doesnt represent any actual shape. Java handles this case with abstract methods.
14.3.9.1. Abstract Methods
Java lets us define a method without implementing it by making the method abstract. An abstract method has no body; it simply has a signature definition followed by a semicolon.25 Here are the rules about abstract methods, and the abstract classes that contain them:
25An abstract method in Java is something like a pure virtual function in C++ (i.e., a virtual function that is declared = 0). In C++, a class that contains a pure virtual function is called an abstract class and may not be instantiated. The same is true of Java classes that contain abstract methods.
That description of the abstract keyword was pretty abstract! Example 14.21 is more concrete. It shows an abstract Shape class and two non-abstract subclasses of it.
EXAMPLE 14.21. An Abstract class and subclasses.
public abstract class Shape { public abstract double area(); public abstract double circumference(); } class Circle extends Shape { protected double r; protected static final double PI = 3.14159265358979323846; public Circle() { r = 1.0; } public Circle(double r) { this.r = r; } public double area() { return PI * r * r; } public double circumference() { return 2 * PI * r; } public double getRadius() { return r; } } class Rectangle extends Shape { protected double w, h; public Rectangle() { w = 0.0; h = 0.0; } public Rectangle(double w, double h) { this.w = w; this.h = h; } public double area() { return w * h; } public double circumference() { return 2 * (w + h); } public double getWidth() { return w; } public double getHeight() { return h; } }
Previous | Table of Contents | Next |