Chapter 10. More on classes

Several of our programs have used classes such as Turtle, GOval, and Color. Classes are quite important to Java programming; it is time to examine some of their features more closely.

10.1. Packages

The full Java system comes with many classes — in fact, at the time of this writing, the latest version includes about 3,000 classes. Moreover, there are many organizations who distribute additional libraries of classes, to make it easier for others to develop software. The acm library that we have been using is one such third-party library, intended for beginning students to be able to work with graphics.

To allow organizing all of these classes, and to address the inevitable problem of having some of the classes having identical names, Java uses the notion of a package to group classes together. An example is the acm.graphics package, which includes classes like GOval and GRect.

The packages distributed with Java have names beginning with java or javax. One such package is the java.awt package, which includes the Color class that we have been using. There are many more packages, several of which we will see in the remainder of this book.

When a program refers to a class, the compiler must be able to determine which package contains that class. To specify the packages, we begin each program with a sequence of import lines.

import acm.graphics.*;
import acm.program.*;
import java.awt.*;

The asterisk ('*') indicates that our program will freely use any combination of the classes from that package. Thus, when the compiler sees a reference to the GOval class, it will examine each of the three packages named to determine which package contains it.

If you omit the import java.awt.*; line but still attempt to access a class in that package, such as the Color class, then the compiler will point to the occurrence of Color in the program and give an error message such as cannot find symbol.

One can also import classes individually rather than use the asterisk. For example, if we know that the only class we will use from the acm.program package is GraphicsProgram, and the only classes we will use from java.awt are Color and Font, then we might write the following.

import acm.graphics.*;
import acm.program.GraphicsProgram;
import java.awt.Color;
import java.awt.Font;

Many professional Java programmers maintain that good Java programs should always import classes individually rather than use '*', mostly because it makes it easy for a reader to quickly see what classes the program depends upon. Importing individual classes is particularly useful when using two packages that contain classes with identical names.

There is one special package: All classes in java.lang are automatically imported, with or without an import line. The package includes several classes, most with some special meaning within the Java base language. Examples of classes in java.lang include String (Chapter 8), Math (later in this chapter), and Object (Chapter 11).

Aside

Java does allow a program to reference classes without first importing them, even when the class is outside java.lang. To do this, you incorporate the package name into the class name every time it appears in the program. Thus, you can omit the import java.awt.Color; line, but if you do this, you must write java.awt.Color in your program every time you would otherwise have written just Color. For example, instead of writing new Color(255, 0, 0), you would write new java.awt.Color(255, 0, 0).

I strongly encourage avoiding this in all cases. In rare cases, though, it is unavoidable. This happens when you are writing a program that uses two identically named types occurring in different packages, such as List, which is in both java.awt and java.util. This can normally be avoided by steering clear of the '*' notation in import lines. But if somehow you have a program that actually uses both types of the same name, there is no other way around it.

10.2. Static methods

There are three categories of methods that can be in a class. We've seen two: instance methods, which are applied to individual objects of the class, and constructors, which are used to manufacture new instances of the class. (Technically, constructors aren't methods, but they have enough similarities that we won't let this technicality bother us.) The third category of method is the static method, which is a method that is applied to the class as a whole, rather than to individual objects of that class. Static methods are sometimes also called class methods.

In the documentation for a class, a static methods is identified by the keyword static. The Math class (in java.lang) is an example of a class with several static methods, including the following.

static int abs(int x)

Returns the absolute value of the parameter x. (Note x is an int here.)

static double abs(double x)

Returns the absolute value of the parameter x. (Note x is a double here.)

static double pow(double basedouble exponent)

Returns the result of raising base to the power exponent (i.e., baseexponent).

static double random()

Returns a pseudorandom number between 0.0 and 1.0.

static double sqrt(double x)

Returns the square root of x.

To invoke a static method, write the class name and method name, separated by a period, followed by parentheses containing any parameter values: Math.sqrt(4) is an example (which gives the value 2.0). Figure 10.1 includes a sample program that splatters blue circles randomly on the screen, as demonstrated in Figure 10.2.

Figure 10.1: The Raindrops program.

  1  import acm.program.*;
  2  import acm.graphics.*;
  3  import java.awt.*;
  4  
  5  public class Raindrops extends GraphicsProgram {
  6      public void run() {
  7          while(true) {
  8              pause(40);
  9              double x = Math.random() * getWidth();
 10              double y = Math.random() * getHeight();
 11              GOval drop = new GOval(x - 5, y - 5, 10, 10);
 12              drop.setFilled(true);
 13              drop.setFillColor(new Color(0, 0, 255));
 14              add(drop);
 15          }
 16      }
 17  }

Figure 10.2: Running the Raindrops program of Figure 10.1.

Notice that though this program must create a GOval object to invoke its setFilled method, there is no need to create a Math object to invoke its random method. Thus, a program could never invoke setFilled as GOval.setFilled, since setFilled requires the program to specify before the period the instance to which the method is applied; however, the program can legally have Math.random, without ever creating any Math instances. This is because setFilled is an instance method, while random is a static method. You can think of the static method as something that the class as a whole does, whereas an instance method is something that an individual object of that class does.

(Since Math contains only static methods, in fact there is never any need to create a Math object. It is possible, though, to have a class that mixes both instance methods and static methods. The String class is an example.)

You may ask: Why are they called static? The word static is being used in this context with its meaning of fixed. Since is just one thing (the class) that can perform the method, the method's destination is fixed; by contrast, the thing (object) that performs an instance method changes depending on what object is specified preceding the period.

Aside

In fact, the choice of the word static is based just as much on historical quirks. The word static derives from Java's predecessor language, C, where the word was used for very different purposes. Over the years it has been adapted for this different purpose, since it seemed vaguely suitable and didn't require adding new keywords into the language. Language designers prefer to avoid adding new keywords because adding a new keyword means that any preexisting program that used that word as a variable name will become broken and thus require modification before being adapted into the new language version.

10.3. Constants

Many classes define constants, which are listed in the documentation as being both static (i.e., associated with the class) and final (i.e., the value doesn't change). They are essentially variables whose value cannot change. An example of a constant can be found in java.lang's Math class.

static final double PI

The value of the mathematical constant π (i.e., 3.14159…).

This gives an easy way to refer to the value of π in a program without having to recite all of its digits. Like static methods, we identify the constant by writing first the name of the class containing the constant, followed by a period and then the name of the constant. Thus, we reference π by writing Math.PI.

double radius = readDouble();
double area = Math.PI * radius * radius;

The Color class defines many more useful constants for referring to individual colors, including black and red. (It also includes the constants BLUE, CYAN, DARK_GRAY, GRAY, GREEN, LIGHT_GRAY, MAGENTA, ORANGE, PINK, WHITE, and YELLOW.)

static final Color BLACK

A Color object approximating the color black.

static final Color RED

A Color object approximating the color red.

Thus, we can modify the body of our BasicBall program of Figure 6.1 to the following.

GOval ball = new GOval(75, 75, 50, 50);
ball.setFilled(true);
ball.setFillColor(Color.RED);
add(ball);

Experienced programmers use constants wherever possible, since they make a program easier to understand. Thus, an expert would consider the above to be preferable to constructing a new Color object to represent red, as we have been doing heretofore.

By convention, constants are usually named using all capital letters, like PI. If there are multiple words in the name, the constant will include an underscore to separate the words. (There are a few constants in the built-in Java library that don't follow this convention. Generally, these predate the firm establishment of this naming convention. An example of such a constant is red in the Color class. The red constant was defined in the earliest version of Java, but this was soon repaired in a later version by also introducing RED to mean the same thing. They had to keep red so that old programs using that name would still compile under newer versions of Java.)