- Special Edition Using Java, 2nd Edition -

Chapter 12

Classes


by Joe Weber and Mike Afergan

Classes are the major building block of an object-oriented structure. Classes are what make objects possible, and without objects, object-oriented programming would not make sense. There are several major advantages to using objects. They enable you to encapsulate data, keeping all information and actions about a particular item separate from the rest of your code. They allow you to build class hierarchies, which enable you to build up more and more complex structures from simpler ones. Lastly, through a technique called polymorphism, dissimilar objects that share a common attribute can be utilized by their similarities.

What Are Classes?

From a common sense view, classes are a way to assemble a set of data and then determine all of the methods needed to access, use, and change that data.

Fundamentally, every class has two major portions. The first portion is that of state. The state of an object is nothing more than the values of each of its variables. If, for instance, you had a class StopLight with one variable, RedGreenYellow, the state of the StopLight would be determined by the value of RedGreenYellow.

public class StopLight{
int RedGreenBlue;
}

The second portion of a class is its tools, or methods. The methods of a class determine the utility that the class has. In the case of the StopLight, it is likely that you would have a method called changeLight(), which would cause the light to change from red to green (probably by changing the RedGreenYellow variable).

public class StopLight{
int RedGreenBlue;
changeLight(){
RedGreenBlue = ++RedGreenBlue%3;
}
}

To distinguish class variables with variables that are parts of methods, class variables are often referred to as fields, or class scope variables. In the previous example, the RedGreenYellow variable would be a field of the StopLight class.
 

Why Use Classes?

When dealing with classes, it is important to remember that classes do not enable us as programmers to do anything more than what we would be able to do without them. While it might be significantly more work, you could write all OOP programs structurally.

So why use classes? The answer to this question is similar to the reason why large companies are divided in departments and sub-departments. By organizing hundreds of people with thousands of tasks, the department architecture provides for a simple distribution of tasks and responsibilities. Furthermore, because the billing department knows how to bill customers, the sales department does not need to worry about those details. By doing this work, the billing department has effectively encapsulated the work of billing within itself.

However, the power of object-oriented programming extends beyond the simple ability to encapsulate functionality in objects. A great deal of the appeal of OOP is its ability to provide inheritance—the ability to create new classes based on old classes. As an example of inheritance, consider a game board. Assume that you wrote a checkers game a couple months ago, and would now like to write a Chess game. By using traditional programming techniques, you would start from scratch, or maybe cut and past some of your old code. Using inheritance can eliminate most of this work. Instead, you can build upon the code you wrote for your checkers game. Override only those methods which behave differently than Checkers, and add only those methods which checkers simply didn’t need.

When new classes inherit the properties of another class, they are referred to as child classes or subclasses. The class from which they are derived is then called a parent or superclass.
 

Another benefit of enclosing data and methods in classes is the OOP characteristic of encapsulation—the ability to isolate and insulate information effectively from the rest of your program. By creating isolated modules, once you have developed a complete class which performs a certain task, you may effectively forget the intricacies of that task and simply use the methods provided by the class. Because the class mechanisms are isolated even if you have to significantly change the inner workings of a given class later, you do not need to modify the rest of your program as long the methods used to gain access to the class do not change. A side benefit of this is that, by placing the data within the class and creating the appropriate methods to manipulate it, you may seal off the data from the rest of the program, thereby preventing accidental corruption of the data.

Finally, the allure of the OOP approach to creating self-sustaining modules is further enhanced by the fact that children of a given class are still considered to be of the same "type" as the parent. This feature, called polymorphism, enables you to perform the same operation on different types of classes as long as they share a common trait. While the behavior of each class might be different, you know that the class will be able to perform the same operation as its parent because it is of the same family tree. For example, if you were to create a Vehicle class, you may later choose to create Truck and Bike classes, each extending the Vehicle class. Although bikes and trucks are very different, they are both still vehicles! Therefore, everything that you are permitted to do with an instance of the Vehicle class you may also do with an instance of the Truck or Bike classes. A car dealership then need not worry if it is selling a Volvo or Saturn. The lot is simply full of vehicles.

What's So New About Object-Oriented Programming?

OOP emphasizes a modular view of programming by forcing you to break down your task into manageable components, each with a specific function. However, unlike procedural functions, which are simply pieced together to form a program, objects are living "creatures" that have the ability to manage themselves, running concurrently with other operations and even existing after the rest of the program has terminated. It is this ability to exist and work with objects as a separate entity that makes OOP a nice match for Java, a network-based language.

In the previous example, while every bike and truck is also a vehicle, a vehicle is not necessarily a bike or a truck. Thus, while the Bike and Truck classes can be treated just like the Vehicle class in Java, you may not perform an operation reserved for the Bike class on an instance of the Vehicle class.
 

Classes in Java

As stated at the beginning of this chapter, classes are the essential building block in any Java applet or application. Classes are used to create objects. When you create an instance of a class, you create an Object. You can include all the code for that object with in the class. In accordance with the object-oriented paradigm, you can later choose to build upon that class to build new programs or enhance your current program.

Bigger and Better Java

Java itself is built from classes that are made available to the general public in the JDK. While there are some limitations, a large number of the classes that make up the Java architecture may themselves be extended. By doing this, you may tailor the classes in the Java API library—especially those in the AWT—to meet your particular needs.

Before you start creating large programs, you must first learn how to create simple classes. In terms of syntax, there are two parts to a class in Java: the declaration and the body. Listing 12.1 is a simple class (that fulfills some of the requirements of the simple game board discussed earlier). Examine this listing to get an idea of what constitutes a class. You can refer to this listing again later as your understanding of classes grows.

Listing 12.1—GameBoard.java A general class for creating a 10 [ts] 10 board game.

public class GameBoard
{
/* This is the beginning a simple game board class that provides the basic */
/* structures necessary for a game board. It may easily be */
/* extended to create a richer game board. */
private static final int WIDTH = 10; /* These are constants */
private static final int HEIGHT = 10; /* that you want to */
private static final int EMPTY = 0; /* keep as standards */
private int board[][];
// This array will keep track of the board
public String myname; // what game is being played
public GameBoard (String gamename) {
board = new int[WIDTH][HEIGHT];
myname = new String(gamename);
}
public final void cleanBoard() {
for (int i = 0; i < WIDTH; i++)
for (int j = 0; j < HEIGHT; j++)
board[i][j] = EMPTY;
}
public synchronized void setSquare(int x, int y, int value) {
board[x][y] = value;
}
public synchronized boolean isEmpty(int x, int y) {
if (board[x][y] == EMPTY)
return(true);
return(false);
}
}

Let’s take a quick look through this class. The first part of any class is the class declaration. Most classes you write will look very similar to GameBoard:

public class GameBoard

Declaring a class states several things, but probably the most important one is the name of the class (GameBoard). In the case of any public class, the name of the class must also match up with the name of the file it is in. In other words, this class must appear in the file GameBoard.java.

The next part of the class is the opening brace. You should notice that there is a brace ({) at the beginning of the class, and if you look all the way down at the bottom there is also a closing brace (}). The braces define the area in the file where the class definitions will exist.

A bit farther down you will see several comments. As you learned in Chapter 8, “Comments,” comments can exist anywhere in the file, and are ignored by the compiler, but help you leave messages for yourself or other programmers.

Next you will see several fields declared. Each of these variables is accessible from any of the methods in the class. When you change them in one method, all the other methods will see the new value.

private static final int WIDTH = 10; /* These are constants */
private static final int HEIGHT = 10; /* that you want to */
private static final int EMPTY = 0; /* keep as standards */
private int board[][];
// This array will keep track of the board
public String myname; // what game is being played

Finally, you should see four methods.


public GameBoard (String gamename) {
board = new int[WIDTH][HEIGHT];
myname = new String(gamename);
}
public final void cleanBoard() {
for (int i = 0; i < WIDTH; i++)
for (int j = 0; j < HEIGHT; j++)
board[i][j] = EMPTY;
}
public synchronized void setSquare(int x, int y, int value) {
board[x][y] = value;
}
public synchronized boolean isEmpty(int x, int y) {
if (board[x][y] == EMPTY)
return(true);
return(false);
}
}

Declaring a Class

In general, Java class declarations have the form:

modifiers class NewClass extends NameofSuperClass implements NameofInterface

where everything in italics is optional. As you can see, there are four properties of the class that may be defined in the declaration:

Modifiers

The modifiers in a class declaration determine how the class can be handled in later development and are very similar to those four modifiers discussed in Chapter 9, “Methods.” While they are usually not extremely important in developing the class itself, they become very important when you decide to create other classes, interfaces, and exceptions that involve that class.

When creating a class, you may choose to accept the default status or you may employ one of the three modifiers: public, final, or abstract.

Public Classes

By placing the modifier public in front of the class declaration, the class is defined to be public. Public classes are, as their name implies, accessible by all objects. This means that they can be used or extended by any object, regardless of its package. Here’s an example:

public class PictureFrame

Also note that public classes must be defined in a file called <ClassName>.java (for example, PictureFrame.java).

"Friendly" Classes

If you choose not to place a modifier in front of the class declaration, the class is created with the default properties. Therefore, you should be aware of what these properties are.

By default, all classes are assigned the "friendly" level of access. This means that while the class may be extended and employed by other classes, only those objects within the same package may make use of this class. Here’s an example of a friendly class:

class PictureFrame

Final Classes

Final classes may not have any subclasses and are created by placing the modifier final in front of the class declaration.

At first, the reason for creating final classes may not be not be evident. Why would you want to prevent other classes from extending your class? Isn't that one of the appeals of the object-oriented approach?

It is important to remember that the object-oriented approach effectively enables you to create many versions of a class (by creating children that inherit its properties but nevertheless change it somewhat). Consequently, if you are creating a class to serve as a standard (for example, a class that will handle network communications), you would not want to allow other classes to handle this function in a different manner. Thus, by making the class final, you eliminate this possibility and ensure consistency.

final class PictureFrame

Abstract Classes

An abstract class, denoted by the modifier abstract, is a class in which at least one method is not complete. This state of not being finished is referred to as abstract.

abstract class PictureFrame

How can a finished class not be complete? In the case of a grammar-checking class that is to be implemented in many languages, there are several methods that would have to be changed for each language-dependent version class. To create a cleaner program, instead of creating an EnglishChecker, a FrenchChecker, and a SpanishChecker class from scratch, you could simply create a GrammarChecker class in which the language-specific methods are declared as abstract and left empty. When ready, you could then create the language-specific classes that would extend the abstract GrammarChecker class and fill in the blanks by redefining these methods with actual code. While you would still end up with separate classes for each language, the heart of your code would be in the GrammarChecker class, leaving only the language-dependent portions for the specific classes.

Because they are not complete, you may not create instances of abstract classes.
 
The class declaration need not be very complex, and most often is very simple. In this example, only one modifier, public, was used; no other classes or interfaces were required:
 

Class Name

Like all other Java identifiers, the only requirements on a class name are that it:

Also, it is general practice to capitalize the first letter in the name of any class.

Although only required for public classes, it is generally a good practice to name the file in which class NewClass is defined NewClass.java. Doing so helps the compiler find NewClass, even if NewClass has not been compiled yet.
 

Super Classes—Extending Another Class

One of the most important aspects of OOP is the ability to use the methods and fields of a class that you have already built. By building upon these simpler classes to build bigger ones, you can save yourself a lot of coding. Possibly even more important, you can greatly reduce the work of finding and fixing bugs in your code. In order to build upon a previous class, you must extend the class in the class declaration.

By extending a super class, you are making your class a new copy of that class but are allowing for growth. If you were simply to leave the rest of the class blank (and not do anything different with the modifiers), the new class would behave identically to the original class. Your new class will have all of the fields and methods declared and/or inherited in the original class.

Does this example look familiar?

If you look at the source of any applet, you see that its declaration resembles the example. In fact, you probably have been extending the java.applet.Applet class without even knowing what you were doing.

Remember the methods that you have been able to use in your applets, such as showStatus(), init(), and keyDown()? Did they appear out of thin air? No, they are drawn from the java.applet.Applet class or one of the classes that it extends, such as java.awt.Component.
 
By extending the java.applet.Applet class, your applet class is able to access and/or implement these methods, thereby providing your applet with a great deal of power.
 

Every class in Java is considered to be an object. By default every class is derived from the java.lang.Object class. So, if your class does not extend any other class, it still extends java.lang.Object.

Multiple-inheritance does not exist in Java. Thus, unlike C++, Java classes may only extend one class.
 

Constructors

Constructors are a very special methods with unique properties and a unique purpose. Constructors are used to set certain properties and perform certain tasks when instances of the class are created. For instance, the constructor for the GameBoard class is:

public GameBoard (String gamename) {
board = new int[WIDTH][HEIGHT];
myname = new String(gamename);
}

Constructors are identified by having the same name as the class itself. Thus, in the GameBoard class, the name of the constructor is GameBoard(). Secondly, constructors do not specify a return argument because they are not actually called as a method. For instance, if you wanted to create an instance of the GameClass, you would have a line that looked like this:

GameClass myGame = new GameClass();

When the new GameClass() is actually instantiated, the constructor method is called.

In general, constructors are used to initialize the class' fields and perform various tasks related to creation, such as connecting to a server or performing some initial calculations.

Also note that overloading the constructor enables you to create an object in several different manners. For example, by creating several constructors, each with a different set of parameters, you could enable yourself to create an instance of the GameBoard class by specifying the name of the game, the values of the board, both, or neither. This practice is prevalent in the Java libraries themselves. As a result, you can create most data types (such as java.lang.String and java.net.Socket) while specifying varying degrees and types of information.

Most programmers choose to make their constructors public. This is because if the level of access for the constructor is less than the level of access for the class itself, another class may be able to declare an instance of your class but will not actually be able to create an instance of that class.
 
However, this loophole may actually be used to your advantage. By making your constructor private, you may enable other classes to use static methods of your class without enabling them to create an instance of it.
 

Finally, constructors cannot be declared to be native, abstract, static, synchronized, or final.

Overriding

It is not legal to create two methods with the same name and parameter list within the same class. After all, doing so would just confuse the whole system (which method would you really want to be calling?). However, one of the purposes of extending a class is to create a new class with added functionality. To allow you to do this, when you inherit another class, you can override any of its methods, by defining a method with the same name and parameter list as a method in the super class. For instance, consider an Elevator class.

class Elevator {
...
private boolean running = true;
...
public void shutDown() {
running = false;
}
}

Now, at some point you realize that this elevator just isn’t very safe, so you decide to create a safer one. You want to extend the old Elevator class, and maintain most of its properties, but change some as well. Specifically you want to check to make sure the elevator car is empty before stopping, so you override the shutDown() method as shown in the following code:

class SaferElevator extends Elevator {
...
public void shutDown() {
if ( isEmpty() )
running = false;

else
printErrorMessage();
}
}

Note that overriding is accomplished only if the new method has the same name and parameter signature as the method in the parent class. If the parameter signature is not the same, the new method will overload the parent method, not override it. For instance, if you had created a class like:

class SaferElevator extends Elevator {
...
public void shutDown(int delay) {
if ( isEmpty() )
running = false;

else
printErrorMessage();
}
}

the shutDown method from the Elevator class would not have changed. Adding the parameter (int delay) to the method changes what is known as the method signature.

When you overload a method, you may not make it more protected than the original method. Because the shutDown method is public in Elevator, you cannot make it private in SaferElevator
 

Creating an Instance of a Class

In order to use a class which you have created, you need to be able to create an instance of that class. An instance is an Object of the type of the class. Any class that you create can be instantiated just like any other data type in Java. For instance, to create an instance of the GameBoard, you would generally declare a variable of that type. The following code fragment shows a class called Checkers creating an instance of the GameBoard class:

public class Checkers{
GameBoard myBoard = new GameBoard();
....
}

As you may have noticed, the one primary difference between declaring an Object type and a primitive type like int is the use of the new keyword. new performs several key tasks:

One additional difference in Java between Objects and primitive types is how they are referenced. Primitive types are always referred to by their value. Object types are always referred to by their reference. This means that in the following code, x and y are not equal at the end, but in w and z myName is the same:
 

int x = 5;
int y = x;
y++; // x = 5, y =6;
GameBoard w = new GameBoard();
GameBoard z = w;
w.myName = “newString”; //Since z and w point to the same object, they now both have the same myName

(c)Referring to Parts of Classes

Now that you have begun to develop classes, let’s examine how they may be used in other classes. As discussed earlier in the section "Why Use Classes?" Java classes may contain instances of other classes that are treated as variables. However, you may also deal with the fields and methods of these class type reference variables. To do so, Java uses the standard dot notation used in most OOP languages. See the following example:

public class Checkers
{

private GameBoard board;
public Checkers() {
board = new game board("Checkers");
board.cleanBoard();
}
...
public void movePiece(int player, int direction) {
java.awt.Point destination;
...
if (board.isEmpty(destination.x, destination.y) )
// code to move piece
}
private void showBoard(Graphics g) {
g.drawString(board.myname,100,100);
drawBoard(g);
}
}

Notice that board is an instance in the GameBoard class, and that the variable myname in the GameBoard class is referenced by board.myname. The general notation is instanceName.methodOrVariableName.

Notice that the variable myname is referred to as board.myname, not as GameBoard.myname. If you try to do so, you get an error resembling:
 
Checkers.java:5: Can't make a static reference to non-static variable
myname in class GameBoard.
 
This is because GameBoard is a type of class, while board is an instance of the class. As discussed in the previous section, when you deal with board, you deal with a specific copy of the GameBoard class. Because myname is not a static variable, it is not a property of the GameBoard class, but rather a property of the instances of that class. Therefore, it cannot be changed or referenced by using GameBoard as the variable name.
 

This Special Variable

You have seen how to refer to other classes. However, what if you want the class to refer to itself? While the reasons to do so may not seem so obvious at first, being able to refer to itself is a capability that is very important for a class. To solve this problem, a unique variable called this is used whenever it is necessary to explicitly refer to the class itself.

In general, there are two situations that warrant use of the this variable:

As seen in the following example, the TextScroll class would then be able to display the information across the bottom of the Presentation class' screen.

public class Presentation extends Applet {
TextScroll scroller;
public void init() {
...
scroller = new TextScroll(this, length_of_text);
scroller.start();
}
...
}
class TextScroll extends Thread {
Presentation screen;
String newMessage;
boolean running;
int size;
TextScroll(Presentation appl, int size) {
screen = appl;
}
public void run() {
while (running) {
displayText();
}
}
void displayText() {
// perform some operations to update what should
// be displayed (newMessage)

screen.showStatus(newMessage);
}
}

See "What are Threads?" Chapter 25 for more information.
 

While the concepts of threads and their uses are discussed in later chapters, note the use of the special this variable in the init() method of the Presentation class as well as the result. This technique is extremely useful and powerful.

Super Special Variable

Along the same lines as this, the special variable super provides access to a class' super class. This is useful when overriding a method, for when doing so, you may want to use a code from the old method as well. For example, if you were creating a new class NewGameBoard that extended the GameBoard class and were overriding the setSquare() method, you might employ the super variable to use the former code without recopying all of it.

class NewGameBoard extends game board {
private static int FIXEDWALL = 99;
// permanent wall, cannot be moved
public static synchronized void setSquare(int x, int y, int value){
if (board[x][y] != FIXEDWALL) {
super.setSquare(x,y,val);
}
}

In the preceding example, you use the super variable to refer to the original version of the setSquare() method, found in the GameBoard class. By doing so, you save yourself the headache of recopying the entire method, while at the same time allowing you to add to the functionality of the setSquare method.

You should also examine how to call the super method if the method you are dealing with is a constructor. It is necessary to call the constructor for a parent class, just as you need to call the constructor for any class. While calling a super constructor is not much different from any other super method, its syntax may seem confusing at first.

public NewGameBoard(String gamename) {
// new code would go here
super(gamename);
}

Note that on a simplistic level, super can be considered equivalent to GameBoard. Consequently, because GameBoard() is the name of the original constructor method, it may be referred to as super().

Variables

Obviously, variables are an integral part of programs and, thus, classes as well. In Chapter 8, “Data Types and Other Tokens,” you examined the various types of variables, but now you must also consider how they are employed in your programs and the different roles they may assume.

When creating variables, whether they are as simple as integers or as complex as derived classes, you must consider how they will be used, what processes will require access to the variables, and what degree of protection you want to provide to these variables.

The ability to access a given variable is dependent on two things: the access modifiers used when creating the variable, and the location of the variable declaration within the class.

See "Literals,” Chapter 9 for more information.
 

 

Class Fields Versus Method Variables

In a class, there are two types of variables: those belonging to the class itself, and those belonging to specific methods.

Those variables declared outside of any methods but within a given class (usually immediately after the class declaration and before any methods) are referred to as fields of the class and are accessible to all methods of it.

In addition, one may declare variables within a method. These variables are local to the method and may only be accessed within that method.

Because method variables exist only for the lifetime of the method, they therefore cannot be accessed by other classes. Consequently, you cannot apply any access modifiers to method variables.

While it is possible to make every field accessible to every class, this is not a prudent practice. First of all, you would be defeating a great deal of the purpose of creating your program from classes. Why do you choose appropriate class names instead of class1, class2, class3, and so on? You do so simply to create a clean program that is easy to code, follow, and debug. For the same reason, by creating various levels of protection, you encapsulate your code into self-sufficient and more logical chunks.

Furthermore, inasmuch as OOP is heavily dependent on the modification of code that you have written beforehand, access restrictions prevent you from later doing something that you shouldn't. (Keep in mind that preventing access to a field does not prevent the use of it.) For example, if you were creating a Circle class, there would most likely be several fields that would keep track of the properties of the class, such as radius, area, border_color, and so on—many of which may be dependent on each other. Although it may seem logical to make the radius field public (accessible by all other classes), consider what would happen if a few weeks later you decided to write the following:

class Circle {
public int radius, area;
...
}
class GraphicalInterface {
Circle ball;
...
void animateBall() {
for (int update_radius = 0; update_radius <= 10; update_radius++){
ball.radius = update_radius
paintBall(ball.area, ball.border_color)
...
}
}
}

This code would not produce the desired result. Although the

ball.radius = update_radius

statement would change the radius, it would not affect the area field. As a result, you would be supplying the paintBall() method with incorrect information. Now, instead, if the radius and area variables where protected, and any update to the radius forced the area to be recomputed, the problem would disappear as shown in the next set of code:

class Circle {
protected int radius, area;

public void newRadius (int rad){
radius = rad;
area = rad *2 * Math.PI;
}


public int radius(){
return radius;
}
public int area (){
return area;
}
}
class GraphicalInterface {
Circle ball;
...
void animateBall() {
for (int update_radius = 0; update_radius <= 10; update_radius++){
ball.newRadius (update_radius);
paintBall(ball.area(), ball.border_color)
...
}
}
}

In the next few sections, you examine the various ways of regulating access and solving this problem.

While it is important to consider the level of access that other objects will have to your fields, it is also important to consider how visible the fields and method variables will be within your class. Where the variable is accessible, a property called its scope, is a very important topic. In general, every variable is accessible only within the block (delimited by the curly braces ( { and } ) in which it is declared. However, there are some slight exceptions to this rule. Examine the following code:

class CashRegister {
public int total;
int sales_value[];
Outputlog log;
void printReceipt(int total_sale) {
Tape.println("Total Sale = $"+ total_sale);
Tape.println("Thank you for shopping with us.");
}
void sellItem(int value) {
log.sale(value);
total += value;
}
int totalSales() {
int num_of_sales, total = 0;
num_of_sales = log.countSales();
for (int i = 1; i <= num_of_sales; i++)
total += sales_value[i];
return(total);
}
}

Now examine some of the variables and their scope:

Variable Name Declared As Scope
total Field global to CashRegister class Entire class
total Local to totalSales() method Within totalSales()
log Field global to CashRegister class Entire class
value Parameter to sellItem() Within sellItem()
i Local to totalSales() within for loop Within the for loop

There are several things to note from the table. Start with the simplest variable, log. log is a field of the CashRegister class and is, therefore, visible throughout the entire class. Every method in the class (as well as other classes in the same package) may access log. Similarly, value, although declared as a parameter, it is nevertheless local to the method sellItem() in which it was declared. While all statements in sellItem() may access value, it may not be accessed by any other methods. Slightly more confusing is the variable i, which is declared not at the beginning of a method but within a for statement. Like log and value that exist only within the block in which they were defined, i is exists only within the for statement in which it was defined. In fact, if you consider a complex for loop like that shown here, i is recreated ( in this case, 10 times).

for (int x = 0; x<10 ;x ++){
for (int i =0;i < num_of_sales; i++ )
...
}

Finally, you arrive at the problem of having two total variables with overlapping scope. While the total field is accessible to all methods, a problem seems to arise in the totalSales() method. In such cases, using the multiply-defined identifier refers to the most local definition of the variable. Therefore, while having no impact on the rest of the class, within the totalSales() the identifier total refers to the local variable total, not the global one. This means that after exiting the totalSales() method, the total class variable is unchanged. In such a situation, you can access the variable with class scope by using the this keyword. To set the class variable total to the method variable total, you would type:

While using an identifier as a field and method variable name does not cause many problems and is considered an acceptable practice, it is preferable to choose a different (and more descriptive) identifier, such as total_sales.

While you are able to use the same identifier as a field and a variable within a method, this does not apply to all code blocks within your code. For example, declaring num_of_sales as your counter within the for block would produce an error.
 

If you do create a method variable with the same name as a field and need to refer to the field rather than the method variable, you may do so with the this variable, as explained earlier in this chapter in the section "This Special Variable."
 

Modifiers

Like the modifiers for classes and methods, access modifiers determine how accessible certain variables are to other classes. However, it is important to realize that access modifiers apply only to the global fields of the class. It makes little sense to speak of access modifiers for variables within methods because they exist only while the method is executing. Afterwards, they are "collected" to free up memory for other variables.

Why Not Make All Variables Fields?

Because all class variables (fields) are accessible to all methods in a given class, why not make all variables fields global to all methods in the class?

The first reason is that you would be wasting a great deal of memory. While local variables (those variables declared within the methods themselves) exist only while the method is executing, fields must exist for the lifetime of the class. Consequently, instead of allocating memory for dozens of fields, by making many of your variables local, you are able to use the same piece of memory over and over again.

The second reason is that making all your variables global would create sloppy programs that would be hard to follow. If you are going to be using a counter only in one method, why not declare it in that method? Furthermore, if all of your variables are global, someone reviewing your code (or you, a few weeks later) would have no idea where the variables were obtaining their values, since there would be no logical path of values being passed from method to method.

friendly

By default, fields are assigned the friendly level of access. This means that while accessible to other classes within the same package, they are not accessible to subclasses of the current class or classes outside of the current package.

int size;

public

Identical to the public access modifier for methods, the public modifier makes fields visible to all classes, regardless of their package, as well as all subclasses. Again, you should make an effort to limit public fields.

public int size;

protected

protected fields may be accessed by all subclasses of the current class, but are not visible to classes outside of the current package.

protected int size;

private

The highest degree of protection, private fields are accessible to all methods within the current class. They are, however, not accessible to any other classes, nor are they accessible to the subclasses of the current class.

private int size;

private protected

private protected fields, like private protected methods, are accessible within the class itself, as well as within subclasses of the current class.

Example: private protected int size;

static

As with methods, placing the modifier static in front of the field declaration makes the field static. static fields are fields of the class whose values are the same in all instances of the class. Consequently, changing a static field in one class will affect that field in all instances of the given class. static fields may be modified in both static and non-static methods.

static int size;

See “Static,” “Methods,” Chapter 9 for more information.
 

final

Although Java does not have preprocessor #define-type statements or constants, there is a very simple way of creating constants—fields whose values cannot change while the program is running. By placing the modifier final in front of a field declaration, you tell the compiler that the value of the field may not change during execution. Furthermore, because it cannot change elsewhere, it is necessary to set the value of all final fields when they are declared as seen in the previous example.

final int SIZE = 5;

If the value cannot change, why not use the value itself within the program? The answer to this question is twofold:

By convention, all letters of constants are capitalized.
 
Furthermore, to save memory, constants are usually made static as well.
 
Although not ignored in the 1.1 release, there are two additional modifiers for fields.
 
When dealing with many threads, there are several problems that can result when multiple threads attempt to access the same data at the same time. While a majority of these problems can be solved by making certain methods synchronized, in future release of Java, you will be able to declare certain fields as threadsafe. Such fields would be handled extra carefully by the Java runtime environment. In particular, the validity of each volatile field will be checked before and after each use.
 
The other heralded keyword, transient, is related closely with Sun's plans to enable the creation of persistent Java applets. In such an environment, transient fields would not be part of the persistent object.
 

Using Methods to Provide Guarded Access

While it may be advantageous to restrict access to certain fields in your class, it is nevertheless often necessary to provide some form of access to those fields. A very intelligent and useful way of doing this is to allow access to restricted fields through less restricted methods, such as in the following example:

class Circle {
private int radius, area;
private Color border_color;
public void setRadius(int update_radius) {
radius = update_radius;
area = Math.PI * radius * 2;
}
public Color getColor() {
return(border_color);
}
public int getRadius() {
return(radius);
}
public int getArea() {
return(area);
}
}
class GraphicalInterface {
Circle ball;
...
void animateBall() {
for (int update_radius = 0; update_radius <= 10;
update_radius++){
ball.setRadius(update_radius);
paintBall(ball.getArea(), ball.getColor() );
}
...
}
}

By limiting access to the radius field to the setRadius() method, you ensure that any change of the radius will be followed by an appropriate change of the area variable. Because you have made the two fields private, you must also provide yourself with the means of accessing them through the various "get"-type methods. These methods are commonly referred to as accessor methods because they provide access to otherwise inaccessible fields. While at first this may seem a bit cumbersome, its benefits by far outweigh its disadvantages. As a result, it is a very widely used approach that is extremely prevalent in the Java API libraries on which Java is heavily dependent.

Using the finalize() Method

Belonging to the java.lang.Object class, and thus present in all classes, is the finalize() method. Empty by default, this method is called by the Java runtime system during the process of garbage collection and, thus, may be used to clean up any ongoing processes before the object is destroyed. For example, in a class that deals with sockets, it is good practice to close all sockets before destroying the object defined by the class. Therefore, you could place the code to close the sockets in the finalize() method. Once the instance of the class is no longer being used in the program and is destroyed, this method would be invoked to close the sockets as required.

The finalize() method is very similar to the ~classname() method in C++.
 

For example,

public class NetworkSender
{

private Socket me;
private OutputStream out;
public NetworkSender(String host, int port) {
try {
me = new Socket(host,port);
out = me.getOutputStream();
}
catch (Exception e) {
System.out.println(e.getMessage();
}
}
public void sendInfo(char signal) {
try {
out.write(signal);
out.flush();
}

catch (Exception e) {
System.out.println(e.getMessage());
}
}
public void disconnect() {
System.out.println("Disconnecting...");
try {
me.close();
}
catch (Exception e)
System.out.println("Error on Disconnect" + e.getMessage());

System.out.println("done.");
}
/* In this case finalize() is the identical to disconnect() /*
/* and only attempts to ensure closure of the socket in the /*
/* case that disconnect() is not called. */
protected void finalize() {
System.out.println("Disconnecting...");
try {
me.close();
}
catch (Exception e)
System.out.println("Error on Disconnect" + e.getMessage());

System.out.println("done.");
}
}

finalize() is declared to be protected in java.lang.Object and thus must remain protected or become less restricted.
 

 

While the finalize() method is a legitimate tool, it should not be relied upon too heavily because garbage collection is not a completely predictable process. This is because garbage collection runs in the background as a low-priority thread and is generally performed when you have no memory left.
 
Consequently, it is a good practice to attempt to perform such "clean-up" tasks elsewhere in your code, resorting to finalize() only as a last resort and when failure to execute such statements will not cause significant problems.
 

Packages

When you start creating a large number of classes for a program, it is helpful to be able to keep them together. The clutter of class files is not unlike how your hard drive would look without subdirectories or folders. Imagine if all the files on your hard drive were placed in a single folder. You would have thousands of files, and you would have to make sure that none of them had the same name.

Class files by themselves must comply with this same arrangement. That’s a fairly ridged requirement. To overcome this, Java has a system called packages. You can think of each package as a subdirectory. You have already seen how a number of packages are used in the Java API. java.awt, for instance is a package, java.lang is another package, and so on.

Packages in Java are groups of Classes. These are similar to libraries in many computer languages. A package of Java classes typically contain related classes. You can imagine a package called Transportation, which would have numerous Classes defined in it such as Car, Boat, Airplane, Train, Rocket, AmphibiousCar, SeaPlane, and so on. Applications that deal with items of this sort might benefit from importing our imaginary Transportation package.

To make a class a member of a package, you must declare it using the package statement:

package Transportation;

Some unique requirements go along with the package statement, however:

Legal Illegal
package Transportation import java.applet.Applet;
import java.awt.Graphics; import java.awt.Graphics;
import java.applet.Applet; package Transportation;

Importing Classes in Packages

Once a file has been declared to be part of a package, the actual name for the class is the package name dot (.), the name of the class. In other words, in our Transportation example, the Car class would be Transportation.Car, where before it would have been simply Car.

This leads to a small problem, with an easy solution. If you write a program and then later decide to make all of the classes a member of a package, how does the compiler find the other files? Before, they were called Car and Van. Now, you must import them as Transportation.Car in order to use them. In other words, as shown here, where before you imported Car, you must now import Trasnportation.Car:

Importing Entire Packages

It is also possible to import the entire contents of a package, or all of the classes in that package. You have probably already seen this done with some of the JDK classes such as java.awt. To import all the classes, replace the individual class name with the wild card (*):

import java.awt.*;

By importing entire packages, you give yourself access to every class in the package. This can be very convenient, because you don’t need to make up a big list like:

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Button;
import java.awt.Canvas;
...

Now, if you’re thinking, “That seems simple; why don’t I just import the entire package all the time?” The answer lies in the fact that there are a couple of drawbacks to importing the entire package:

Using a Class Without Importing It

You may have not realized this before, but it is not necessary to actually import a class before you use it. Ordinarily, classes in the null package (default) and which reside in the same physical directory can be used without doing anything. For instance, if there are two classes Car and Van in the same directory, you can create an instance of Car in the Van class without actually importing the Car class. Listings 12.1 and 12.2 show two such classes.

Listing 12.2 A simple class file for the Car class.

//Car is just a generic class with a few variables
public class Car {
int wheels;
int tires;
int speed;
//simple constructor
public Car (int inWheels, int inTires, int inSpeed){
wheels=inWheels;
tires = inTires;
speed = inSpeed;

}
}
Listing 12.3 A simple class file for Van, which uses the Car class.

//The Van class is another simple class, but uses the Car class
public class Van {
//The Car class is used here without being imported
Car theCar;
int doors;
//simple constructor
public Van (Car inCar, int inDoor){
theCar= inCar;
doors= inDoor;
}
}

When you place a class in a package, you can still use the class with out importing it. The only difference is that you must use the full class name when declaring the instance. Listings 12.4 and 12.5 are identical to 12.2 and 12.3 except that Car is a member of the Transportation package.

Listing 12.4 A simple class file for the Car class in a package.

package Transportation;
//Car is just a generic class with a few variables
public class Car {
int wheels;
int tires;
int speed;
//simple constructor
public Car (int inWheels, int inTires, int inSpeed){
wheels=inWheels;
tires = inTires;
speed = inSpeed;

}
}

Listing 12.5 A simple class file for Van, which uses the Car class in a package.

//The Van class is another simple class, but uses the Car class
public class Van {
//The Car class is used here without being imported
Transportation.Car theCar;
int doors;
//simple constructor
public Van (Car inCar, int inDoor){
theCar= inCar;
doors= inDoor;
}
}

While you do not need to import a package to use the classes, doing so affords a shorthand way to refer to classes defined in the package. Specifically, in the previous example, if the package was imported:

 

import Transportation.Car;

 
to create an object of Class Car, you would not need Transportation in front of every Car reference, and the code would look otherwise identical to listing 12.2.
 

Using Packages to Organize Your Code

Packages are more than just a shortcut. They are a way of keeping things organized.

Java itself comes with a built-in set of packages, as shown in table 12.1.

Table 12.1 Standard Java Packages

Package Description
java.applet Contains classes needed to create Java applets that run under Netscape 2.0 (or greater), HotJava, or other Java-compatible browsers.
java.awt Contains classes helpful in writing platform-independent graphic user interface (GUI) applications. This comes with several subpackages including java.awt.peer and java.awt.image.
java.io Contains classes for doing I/O (input and output). This is where the data stream classes are kept.
java.lang Contains the essential Java classes. java.lang is implicitly imported, so you don’t need to import its classes.
java.net Contains the classes used for making network connections. These are used in tandem with java.io for reading and writing data from the network.
java.util Contains other tools and data structures, such as encoding, decoding, vectors, stacks, and more

Additional packages are also available commercially.

The one feature to notice about these classes is how Sun Microsystems has used the packages to group similar classes together. When you set out to construct a program, you might be tempted to place the entire program in a package. For instance, say you were writing a Pac Man game. You might be tempted to place all of the classes in a package called Pac. Would this be a good idea? Probably not, but it all depends on your implementation.

The odds are that your Pac Man game will include a lot of code that is likely to be used by other arcade style games you have written. For instance, you might create what is known as a game sprite engine. It’s probably a more far-sighted approach to place all of the elements for the game-sprite in their own package. Then place only those classes which are specific to the Pac Man game in the Pac package. Later you can go back and add to the game-sprite package without disrupting the readability of your Pac Man game.


Previous PageTOCNext Page

| Previous Chapter | Next Chapter |

| Table of Contents | Book Home Page |

| Que Home Page | Digital Bookshelf | Disclaimer |


To order books from QUE, call us at 800-716-0044 or 317-361-5400.

For comments or technical support for our books and software, select Talk to Us.

© 1996, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon and Schuster Company.