[go: up one dir, main page]

0% found this document useful (0 votes)
110 views36 pages

An Introduction To Classes: Chapter Goals

java chapter 3

Uploaded by

Ani Ani
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
110 views36 pages

An Introduction To Classes: Chapter Goals

java chapter 3

Uploaded by

Ani Ani
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 36

An Introduction to Classes

3
CHAPTER

Chapter Goals
◆ To become familiar with the process of implementing classes

◆ To be able to implement simple methods

◆ To understand the purpose and use of constructors

◆ To understand how to access instance variables

◆ To realize how the process of encapsulation helps in structuring a program

◆ To understand the copy behavior of object references

◆ To write a Console class that makes keyboard input more convenient

103
104 Chapter 3. An Introduction to Classes

You have learned about the number and string data types of Java. Although it is
possible to write interesting programs using nothing but numbers and strings, most
useful programs need to manipulate data items that are more complex and more
closely represent entities in the real world. Examples of these data items are bank
accounts, employee records, graphical shapes, and so on.
The Java language is ideally suited for designing and manipulating such data items,
or objects. In Java, you define classes that describe the behavior of these objects. In this
chapter, you will learn how to define classes that describe objects with very simple
behavior. To implement more complex behavior, you will need to know more about
control structures in Java, which is the topic of Chapters 5 and 7.

3.1 Determining Object Behavior

In this section, you will learn how to create a simple class that describes the behavior
of a bank account. First, you will see how to use the class, assuming that someone has
already defined it. Next, you will see how to implement the class and its methods.
Before you start programming, you need to understand how the objects of your
class behave. Consider what kind of operations you can carry out with a bank ac-
count. You can

◆ Deposit money
◆ Withdraw money
◆ Get the current balance

In Java, these operations are expressed as method calls. Let’s suppose you have an
object harrysChecking of type BankAccount. Then you’ll want to be able to call
methods such as the following:
harrysChecking.deposit(2000);
harrysChecking.withdraw(500);
System.out.println("Balance: " + harrysChecking.getBalance());
That is, the set of methods

◆ deposit
◆ withdraw
◆ getBalance

forms the behavior of the BankAccount class. The behavior is the complete list of
methods that you can apply to objects of a given class. (This is also called the interface
of the class, but in Java, the word interface has a more restricted meaning; see Chapter
9.) You can think of an object of type BankAccount as a “black box” that can carry
out its methods.
For a more complex class, it takes some amount of skill and practice to discover the
appropriate behavior that makes the class useful and is reasonable to implement. You
3.1 Determining Object Behavior 105

will learn more about this important aspect of class design in Chapter 14. For now,
we will work with simple classes for which the behavior is very straightforward.
The behavior of our BankAccount class is simple, but it lets you carry out all
important operations that commonly occur with bank accounts. For example, here
is how you can transfer an amount from one bank account to another:
// transfer from one account to another
double transferAmount = 500;
momsSavings.withdraw(transferAmount);
harrysChecking.deposit(transferAmount);
And here is how you can add interest to a savings account:
double interestRate = 5; // 5% interest
double interestAmount =
momsSavings.getBalance() * interestRate / 100;
momsSavings.deposit(interestAmount);
Finally, we have to discuss how to construct objects of the BankAccount class. Recall
from chapter 1 that object variables such as harrysChecking are references to objects.
Suppose you declare an object variable:
BankAccount harrysChecking;
This object variable does not refer to any object at all. If you were to try to invoke a
method on this variable, the compiler would tell you that the variable has not been
initialized. To initialize the variable, you need to create a new BankAccount object.
You do this by calling
new BankAccount()
This call creates a new object and returns a reference to the newly created object (see
Figure 1). To use the object, you must assign that reference to an object variable (see
Figure 2):
BankAccount harrysChecking = new BankAccount();
We will implement the BankAccount so that a newly created bank account has a
zero balance. Here is a scenario to open a new account and to deposit some money:
// open a new account
double initialDeposit = 1000;
BankAccount harrysChecking = new BankAccount();
// constructed with zero balance
harrysChecking.deposit(initialDeposit);

Figure 1
BankAccount

Creating a New balance


Object
106 Chapter 3. An Introduction to Classes

harrysChecking

BankAccount

balance 0

Figure 2

Initializing an Object Variable

As you can see, you can use objects of the BankAccount class to carry out meaningful
tasks, without knowing how the BankAccount objects store their data or how the
BankAccount methods do their work. This is an important aspect of object-oriented
programming.

3.2 Defining Methods

Now that you understand how to use objects of the BankAccount class, let’s get
started designing the Java class that implements this behavior. As you already know,
you need to implement a class to describe object behavior:
public class BankAccount
{ BankAccount methods
BankAccount data
}
We have identified three methods:
public class BankAccount
{ public void deposit(double amount)
{ method implementation
}
public void withdraw(double amount)
{ method implementation
}
public double getBalance()
{ method implementation
}
BankAccount data
}
3.2 Defining Methods 107

Here we start out with the headers of methods. A method header consists of the
following parts:

◆ An access specifier (such as public)


◆ The return type of the method (such as double or void)
◆ The name of the method (such as deposit)
◆ A list of the parameters of the method

Let us consider each of these parts in detail.


The access specifier controls which other methods can call this method. Most
methods should be declared as public. That way, all other methods in your program
can call them. (Occasionally, it can be useful to have methods that are not so widely
callable—turn to Chapter 9 for more information on this issue.)
The return type is the type of the value that the method computes. For exam-
ple, the getBalance method returns the current account balance, which will be a
floating-point number, so its return type is double. On the other hand, the deposit
and withdraw methods don’t return any value. They just update the current balance
but don’t return it. That is, you can write

harrysChecking.deposit(500); // Ok

but you can’t write

double b = harrysChecking.deposit(500); // Error

To indicate that a method does not return a value, use the special type void. Both
the deposit and withdraw methods are declared with return type void.
The parameters are the inputs to the method. The deposit and withdraw meth-
ods each have one parameter: the amount of money to deposit or withdraw. You
need to specify the type of the parameter, such as double, and a name for the pa-
rameter, such as amount. The getBalance method has no parameters. In that case,
you still need to supply a pair of parentheses () behind the method name.
If a method has more than one parameter, you separate them by commas. For
example,

public class Rectangle


{ . . .
public void translate(double x, double y)
{ method implementation
}
. . .
}

Once you have specified the method header, you must supply the implementation
of the method, in a block that is delimited by braces { . . . }. You will see how to
implement the BankAccount methods in Section 3.4.
108 Chapter 3. An Introduction to Classes

Java Syntax
3.1 Method Implementation
public class ClassName
{ . . .
accessSpecifier returnType methodName
(parameterType parameterName, . . . )
method implementation
}
. . .
}

Example:
public class BankAccount
{ . . .
public void deposit(double amount)
{ balance = balance + amount;
}
. . .
}

Purpose:
To define the behavior of a method

3.3 Instance Variables

Each object must store its current state: the set of values that describe the object and
that influence how an object reacts to method calls. In the case of our simple bank
account objects, the state is the current balance of the bank account. (A more complex
bank account might have a richer state, perhaps the current balance together with
the interest rate paid on the current balance.) Each object stores the state in one or
more instance variables:
public class BankAccount
{ . . .
private double balance;
}
An instance variable declaration consists of the following parts:

◆ An access specifier (such as private)


◆ The type of the variable (such as double)
◆ The name of the variable (such as balance)

Each object of a class has its own copy of the instance variables. For exam-
ple, if harrysChecking and momsSavings are two objects of the BankAccount
3.3 Instance Variables 109

harrysChecking

BankAccount

balance 0

momsSavings

BankAccount

balance 7500

Figure 3

Instance Variables

class, then each object has its own balance field, harrysChecking.balance and
momsSavings.balance (see Figure 3).
Instance variables are generally declared with the access specifier private. That
means, they can be accessed only by the methods of the same class, not by any other
method. In particular, the balance variable can be accessed only by the deposit,
withdraw, and getBalance methods.
In other words, if the instance variables are declared private, then all data access
must occur through the public methods. Thus, the instance variables of an object are
effectively hidden from the programmer who uses a class. They are of concern only
to the programmer who implements the class. The process of hiding data is called
encapsulation. Although it is theoretically possible in Java to leave instance variables
unencapsulated (by defining them as public), that is very uncommon in practice.
We will always make all instance variables private in this book.
For example, because the balance instance variable is private, you cannot access
the instance variable in other code:
double b = harrysChecking.balance; // Error
But you can call the public getBalance method to inquire about the balance:
double b = harrysChecking.getBalance(); // OK
110 Chapter 3. An Introduction to Classes

Java Syntax
3.2 Instance Variable Declaration
class ClassName
{ . . .
accessSpecifier type variableName;
}

Example:
public class BankAccount
{ . . .
private double balance;
}

Purpose:
To define a variable that is present in every ob-
ject of a class

Note that there is no equivalent setBalance method to set the balance to a par-
ticular value. With a real bank account, you cannot simply set the balance to any
desired value; you must update the balance the hard way, through withdrawals and
deposits. The class behavior captures this not always convenient fact.
The BankAccount class is so simple that it is not obvious what benefit you gain
from the encapsulation. The primary benefit of the encapsulation mechanism is the
guarantee that an object cannot accidentally be put into an incorrect state. For exam-
ple, suppose you want to make sure that a bank account is never overdrawn. You can
simply implement the withdraw method so that it refuses to carry out a withdrawal
that would result in a negative balance. On the other hand, if any code could freely
modify the balance instance variable of a BankAccount object, then it would be an
easy matter to store a negative number in the variable.
We will have more to say about the importance of encapsulation in later chapters.
For now, we will simply require that all instance variables be declared private. Hence
their values can be examined and set only by the methods of their own class.

3.4 Implementing Methods

You must provide an implementation for every method of the class. Here is the im-
plementation of the three methods of the BankAccount class. Note that these meth-
ods do not protect the account from being overdrawn. We did not yet introduce the
necessary Java statement to carry out that check. You will need to wait until Chapter
5 to see how to implement this enhancement.
public class BankAccount
{ public void deposit(double amount)
{ balance = balance + amount;
}
3.4 Implementing Methods 111

Java Syntax
3.3 The return Statement
return expression ;
or
return;

Example:
public class BankAccount
{ public double getBalance()
{ return balance;
}
. . .
}

Purpose:
To obtain the value that a method returns, and
exit the method immediately. The return value
becomes the value of the method call expres-
sion.

public void withdraw(double amount)


{ balance = balance - amount;
}
public double getBalance()
{ return balance;
}

private double balance;


}
The implementation of the methods is straightforward. When some amount of
money is deposited or withdrawn, the balance increases or decreases by that amount.
The getBalance method simply returns the current balance.
Inside the getBalance method, we use a return statement to obtain a value,
namely the current balance, and return it as the result of the method call.
Consider the definition of the withdraw method:
public void withdraw(double amount)
{ balance = balance - amount;
}

Now look at a particular invocation of this method:


momsSavings.withdraw(500);
Obviously, the call to the withdraw method depends on two values: the object
reference momsSavings and the value 500. Clearly, when the method executes, the
112 Chapter 3. An Introduction to Classes

parameter amount is set to 500. This parameter is called an explicit parameter, be-
cause it is explicitly named in the method definition. However, the bank account
reference is not explicit in the method definition—it is called the implicit parameter of
the method. Inside each method, the object reference whose name is the keyword
this refers to the implicit parameter object. For example, in the preceding method
invocation, this was set to momsSavings.
Every method has one implicit parameter. The type of the implicit parame-
ter is the class that defines the method. You don’t give the implicit parameter a
name. It is always called this. (There is one exception to the rule that every meth-
od has an implicit parameter: static methods do not. We will discuss them in Chap-
ter 6.)
Methods can have any number of explicit parameters, or no explicit parameter at
all. You must give a type and a name for each explicit parameter. When you call a
method, you supply the value for the implicit parameter before the method name,
separated by a dot (.), and you supply the values for the explicit parameters inside
parentheses after the method name:
implicitParameterValue.methodName ( explicitParameterValues );
Next, look again closely at the implementation of the withdraw method. In the
statement
balance = balance - amount;
it is clear what amount means; it is the value of the explicit amount parameter. But
what is balance? There is a balance instance variable in the BankAccount class,
denoting the balance of a particular account. Which account? Java uses a convenient
shorthand. When you refer to an instance variable in a method, you automatically
refer to the instance variable of the object for which the method was called (implicit param-
eter). In other words, the withdraw method actually executes the statement
this.balance = this.balance - amount;
For example, when called with
momsSavings.withdraw(500);
the method call computes
momsSavings.balance = momsSavings.balance - 500;

3.5 Constructors

There is only one remaining issue with the BankAccount class. We need to define
the default constructor.
The code for a constructor sets all instance variables of the object. The purpose of
a constructor is to initialize the instance variables of an object.
3.5 Constructors 113

public class BankAccount


{ public BankAccount()
{ balance = 0;
}
. . .
}

Constructors always have the same name as their class. Similar to methods, con-
structors are generally declared as public to enable any code in a program to con-
struct new objects of the class. Unlike methods, though, constructors do not have
return types.
Constructors are always invoked together with the new operator:
new BankAccount()

The new operator allocates memory for the object, and the constructor initializes
it. The value of the new operator is the reference to the newly allocated and con-
structed object. In most cases, you want to store that object reference in an object
variable:
BankAccount harrysChecking = new BankAccount();
// sets harrysChecking to a new account with zero balance

Constructors are not methods. You cannot invoke a constructor on an existing object.
For example, the call

harrysChecking.BankAccount(); // Error

is illegal. You can use a constructor only in combination with the new operator.
The constructor that we just defined is a default constructor—it takes no parame-
ters. The BankAccount default constructor sets the bank balance to 0. Some default
constructors work harder than that. For example, the default constructor of the Date
class in the java.util package constructs an object that stores the current date and
time.
If you do not initialize an instance variable that is a number, it is initialized au-
tomatically to zero. In this regard, instance variables act differently than local vari-
ables! Therefore, you didn’t actually have to initialize the balance instance variable
to zero. Nevertheless, it is a matter of good style to initialize every instance variable
explicitly. On the other hand, an object variable is initialized to a special value called
null, which indicates that the object variable does not yet refer to an actual object.
(See Section 3.9.)
Many classes have more than one constructor. For example, you can supply a
second constructor for the BankAccount class that sets the balance instance variable
to an initial balance, which is a parameter of the constructor:
public class BankAccount
{ public BankAccount()
{ balance = 0;
}
114 Chapter 3. An Introduction to Classes

public BankAccount(double initialBalance)


{ balance = initialBalance;
}
. . .
}

The second constructor is used if you supply a number as a construction parameter:


BankAccount momsSavings = new BankAccount(5000);
// sets momsSavings.balance to 5000

Now there are two constructors with the same name. (You have no choice how
to name a constructor—it must have the same name as the class.) Whenever you
have multiple methods (or constructors) with the same name, the name is said to be
overloaded. The compiler figures out which one to call by looking at the parameters.
For example, if you call
new BankAccount()

then the compiler picks the first constructor. If you call


new BankAccount(5000)

then the compiler picks the second constructor. But if you call
new BankAccount("lotsa moolah")
then the compiler generates an error message—there is no constructor that takes a
parameter of type String.
We have now completed the implementation of the BankAccount class. Here is
the complete source code for this class.

Class BankAccount.java
public class BankAccount
{ public BankAccount()
{ balance = 0;
}

public BankAccount(double initialBalance)


{ balance = initialBalance;
}

public void deposit(double amount)


{ balance = balance + amount;
}

public void withdraw(double amount)


{ balance = balance - amount;
}
3.5 Constructors 115

Java Syntax
3.4 Constructor Implementation
class ClassName
{ . . .
accessSpecifier ClassName
(parameterType parameterName, . . .)
{ constructor implementation
}
. . .
}

Example:
public class BankAccount
{ . . .
public BankAccount(double initialBalance)
{ balance = initialBalance;
}
. . .
}

Purpose:
To define the behavior of a constructor. Construc-
tors are used to initialize newly created objects.

public double getBalance()


{ return balance;
}

private double balance;


}

Common Error 3.1


◆ Forgetting to Call the Constructor

A very common error for beginners is to allocate an object reference, but not an actual object.

◆ BankAccount myAccount;
◆ myAccount.deposit(1000000);
◆ // Error—myAccount not initialized

The myAccount variable holds a reference to an object. You still have to make the object. There

is only one way to make an object—to construct it with the new operator.

◆ BankAccount myAccount = new BankAccount();
116 Chapter 3. An Introduction to Classes

Common Error 3.2


◆ Trying to Reset an Object by Calling
◆ a Constructor

◆ The constructor is invoked only when an object is first created. You cannot call the constructor
◆ to reset an object:

BankAccount harrysChecking = new BankAccount();

harrysChecking.withdraw(500);

harrysChecking.BankAccount(); // Error—can’t reconstruct object

◆ The default constructor sets a new account object to a zero balance, but you cannot invoke a
◆ constructor on an existing object. The remedy is simple: Make a new object and overwrite the
◆ current one.

◆ harrysChecking = new BankAccount(); // OK

Common Error 3.3


◆ Trying to Call a Method without
◆ an Implicit Parameter

◆ Suppose your main method contains the instruction
◆ withdraw(30); // Error

◆ The compiler will not know which account to access to withdraw the money. You need to
◆ supply an object reference of type BankAccount:

◆ BankAccount harrysChecking = new BankAccount();
◆ harrysChecking.withdraw(30);

◆ However, there is one situation in which it is legitimate to invoke a method without, seem-
◆ ingly, an implicit parameter. Consider the following modification to the BankAccount class.
◆ Add a method to apply the monthly account fee:

◆ public class BankAccount
◆ { . . .
◆ void monthlyFee()
◆ { final double MONTHLY_FEE = 10;
◆ withdraw(MONTHLY_FEE);
◆ // OK, withdraw from this account
◆ }
◆ }

◆ That means to withdraw from the same account object that is carrying out the monthlyFee
◆ operation. In other words, the implicit parameter of the withdraw method is the (invisible)
◆ implicit parameter of the monthlyFee method.
3.5 Constructors 117

◆ If you find it confusing to have an invisible parameter, you can always use the this param-
◆ eter to make the method easier to read:

◆ class BankAccount
◆ { . . .
◆ public void monthlyFee()
◆ { final double MONTHLY_FEE = 10;
◆ this.withdraw(MONTHLY_FEE);
// withdraw from this account

}

}

Advanced Topic 3.1


◆ Overloading

◆ When the same name is used for more than one method or constructor, the name is overloaded.
◆ This is particularly common for constructors, because all constructors must have the same
◆ name—the name of the class. In Java you can overload methods and constructors, provided
◆ the parameter types are different. For example, the PrintStream class defines many methods,
◆ all called print, to print various number types and to print objects:

◆ class PrintStream
◆ { public void print(int n) { . . . }
◆ public void print(double a) { . . . }
◆ . . .
◆ }

◆ When the print method is called,

print(x);

◆ the compiler looks at the type of x. If x is an int value, the first method is called. If x is a
◆ double value, the second method is called. If x does not match the parameter type of any of
◆ the methods, the compiler generates an error.

For overloading purposes, the type of the return value does not matter. You cannot have two

methods with identical names and parameter types but different return values.

Advanced Topic 3.2


◆ Calling One Constructor from Another

Consider the BankAccount class. It has two constructors: a default constructor to initialize the
◆ balance with zero, and another constructor to supply an initial balance. In our case, the default
◆ constructor is only one line long. In general, though, if the default constructor needs to initialize
118 Chapter 3. An Introduction to Classes

◆ several instance variables, it can be convenient to have the default constructor call another
◆ constructor of the same class instead. There is a shorthand notation to achieve this:

◆ class BankAccount
◆ { public BankAccount (double initialBalance)
◆ { balance = initialBalance;
◆ }
◆ public BankAccount()
◆ { this(0);
◆ }
◆ . . .
◆ }

◆ The command this(0); means “Call another constructor of this class and supply the value
◆ 0.” Such a constructor call can occur only as the first line in another constructor.
◆ This syntax is a minor convenience. We will not use it in this book. Actually, the use of
◆ the this keyword is a little confusing. Normally, this denotes a reference to the implicit
◆ parameter, but if this is followed by parentheses, it denotes a call to another constructor of
◆ this class.

Productivity Hint 3.1


◆ Keyboard Shortcuts for Mouse Operations

◆ Programmers spend a lot of time with the keyboard and the mouse. Programs and documen-
◆ tation are many pages long and require a lot of typing. The constant switching among the
◆ editor, compiler, and debugger takes up quite a few mouse clicks. The designers of programs
◆ such as a Java integrated development environment have added some features to make your
◆ work easier, but it is up to you to discover them.
◆ Just about every program has a user interface with menus and dialog boxes. Click on a
◆ menu and click on a submenu to select a task. Click on each field in a dialog box, fill in the
◆ requested answer, and click the OK button. These are great user interfaces for the beginner,
◆ because they are easy to master, but they are terrible user interfaces for the regular user. The
◆ constant switching between the keyboard and the mouse slows you down. You need to move
◆ a hand off the keyboard, locate the mouse, move the mouse, click the mouse, and move the
◆ hand back onto the keyboard. For that reason, most user interfaces have keyboard shortcuts:
◆ combinations of keystrokes that allow you to achieve the same tasks without having to switch
◆ to the mouse at all.
◆ All Microsoft Windows applications use the following conventions:

◆ ◆ The Alt key plus the underlined letter in a menu name (such as the F in “File”) pulls
◆ down that menu. Inside a menu, just type the underlined character in the name of a
◆ submenu to activate it. For example, Alt + F O selects “File” “Open”. Once your fingers
◆ know about this combination, you can open files faster than the fastest mouse artist.

◆ ◆ Inside dialog boxes, the Tab key is important; it moves from one option to the next.
◆ The arrow keys move within an option. The Enter key accepts the entire dialog, and
◆ Esc cancels it.
3.6 Putting a Class to Work 119

◆ ◆ In a program with multiple windows, Ctrl + Tab usually toggles through the windows
◆ managed by that program, for example between the source and error window.

◆ Alt + Tab toggles between applications, letting you toggle quickly between, for exam-

ple, the compiler and a folder explorer program.

◆ ◆ Hold down the Shift key and press the arrow keys to highlight text. Then use Ctrl +
◆ X to cut the text, Ctrl + C to copy it, and Ctrl + V to paste it. These keys are easy to
◆ remember. The V looks like an insertion mark that an editor would use to insert text.
◆ The X should remind you of crossing out text. The C is just the first letter in “copy”.
◆ (OK, so it is also the first letter in “Cut”—no mnemonic rule is perfect.) You find these
◆ reminders in the Edit menu.

◆ Of course, the mouse has its use in text processing: to locate or select text that is on the same
◆ screen but far away from the cursor.
◆ Take a little bit of time to learn about the keyboard shortcuts that the designers of your
◆ programs provided for you, and the time investment will be repaid many times during your
◆ programming career. When you blaze through your work in the computer lab with keyboard
◆ shortcuts, you may find yourself surrounded by amazed onlookers who whisper, “I didn’t
◆ know you could do that.”

3.6 Putting a Class to Work

In the last five sections, you saw how a class implementer designs and implements
a class: by determining the desired behavior and implementing the methods of the
class. Now let’s see how a class user can make use of the designer’s efforts. The class
user is still a programmer who wants to solve a particular problem with a class,
without necessarily having to think about how the class was implemented. (The
class user is not the same as the program user, a nonprogrammer who has no interest
at all in how the program is put together.) Of course, as a beginning Java programmer,
you are often simultaneously the implementer and user of your own classes. You
should nevertheless develop a “split personality”. When designing a class, think of the
concept that the class represents (such as a bank account), and think of the behavior
that you—or any other programmers who might need to write programs involving
bank accounts—need to utilize. Conversely, when using a class, whether it is one of
your own creation or supplied in a library, you should not think of the internals of
the class.
Let’s try this out by writing a program that puts the BankAccount class to work.
We want to study the following scenario:

A savings account is created with a balance of $10,000. For two years in a row, add 5%
interest. How much money is in the account after two years?

Now you need two classes: the BankAccount class that we developed in the preceding
sections, and a second class that we will call BankAccountTest. The main method
120 Chapter 3. An Introduction to Classes

of the BankAccountTest class constructs a BankAccount object, adds the interest


twice, then prints out the balance.

Program BankAccountTest.java
public class BankAccountTest
{ public static void main(String[] args)
{ BankAccount account = new BankAccount(10000);

final double INTEREST_RATE = 5;

double interest;

// compute and add interest for one period

interest = account.getBalance() * INTEREST_RATE / 100;


account.deposit(interest);

System.out.println("Balance after year 1 is $"


+ account.getBalance());

// add interest again

interest = account.getBalance() * INTEREST_RATE / 100;


account.deposit(interest);

System.out.println("Balance after year 2 is $"


+ account.getBalance());
}
}
You can distribute your classes over multiple files, or you may find it more conven-
ient to keep all classes of your program together in a single file. If you do the latter,
however, there is one caveat. A Java source file can contain only one public class.
Therefore, you must declare the class with the main method as public, and you can-
not specify the public attribute for any other class in the same file. (You do not de-
clare classes as private.) Also, you must make sure that the name of the file matches
the name of the public class. For example, you must store a program file with two
classes BankAccount and BankAccountTest in a file BankAccountTest.java, not
BankAccount.java.

3.7 Discovering Classes

When you have a programming problem, you need to discover one or more classes
that help you solve the problem. Discovering useful classes is an important skill that
you will practice throughout your first Java programming course. In Chapter 14 we
will approach this issue systematically, but for now we just want to give you a useful
3.7 Discovering Classes 121

rule of thumb how to go about discovering classes. That rule of thumb is to look for
nouns in the description of the problem that you want to solve. Some of the nouns may
suggest useful classes. Conversely, some of the verbs may suggest useful methods of
those classes.
Let’s try this out with one of the programs of the preceding chapter. Recall that
you studied a program that asks a user to specify the number of coins in a purse and
then prints out the total amount of money in the purse.
There are three nouns in the problem description: coin, purse, and money. What is
a coin? A coin has a name (such as “quarter”) and a dollar value (such as $0.25). A
purse contains a collection of coins.
We will turn these nouns into classes in a moment. The noun money can lead to
a useful class, for example, if you want to model different currencies. In a simple
example, though, you can just use a floating-point number to store a dollar amount,
so we won’t make a separate money class now.
A Coin object needs to remember its name and dollar value. A constructor sets
the name and value, and you need two methods to find out the name and value of a
coin. Actually, there is a complexity with coin names. Given a singular name (such as
“penny” or “quarter”), the computer has no way of determining the plural form (such
as “pennies” and “quarters”). Simply store the plural form. (A better way would be to
store both names and pick the correct one, depending on the coin count. However,
you don’t yet know enough Java to implement this enhancement.)
The Coin class is a very simple class, consisting of a constructor, two methods,
and two instance variables. Here it is, without much further ado.
class Coin
{ // a constructor for constructing a coin

public Coin(double aValue, String aName)


{ value = aValue;
name = aName;
}

// methods to access the value and name

public double getValue()


{ return value;
}

public String getName()


{ return name;
}

// instance variables to store the value and name

private double value;


private String name;
}
122 Chapter 3. An Introduction to Classes

For example, here is how you construct a quarter:


Coin coinType = new Coin(0.25, "quarters");

Let’s put this class to work. How many coins of that type does a user have?
System.out.println("How many " + coinType.getName()
+ " do you have?");
int coinCount = console.readInt();

What is that set of coins worth?


double value = coinCount * coinType.getValue();
Next, let’s turn our attention to the concept of a purse. A purse contains a collection
of coins. You don’t yet know how to implement such a collection, and since we are
currently interested in the total value and not the individual coins, we will ignore
this aspect of a purse and simply have the purse store the total value. What are useful
methods for a purse? We will need to add more coins to the purse and to get the total
value of the purse. Here is the Purse class with these two methods:
class Purse
{ // default constructor makes purse with zero total

public Purse()
{ total = 0;
}

// methods to add coins and to get the total

public void addCoins(int coinCount, Coin coinType)


{ double value = coinCount * coinType.getValue();
total = total + value;
}

public double getTotal()


{ return total;
}

// instance variable to store the total

private double total;


}
This class is also convenient to use. You can add coins to the purse.
Coin nickels = new Coin(0.05, "nickels");
thePurse.add(3, nickels);
How much money is in the purse after adding a few coins?
System.out.println("The total value is $"
+ thePurse.getTotal());
3.7 Discovering Classes 123

Now that you have discovered and implemented these simple classes, the
program is easy. First, make a Purse object. For each of the four coin types,
find out how many coins the user has, and call addCoins. Finally, print the total
value.
public class Coins6
{ public static void main(String[] args)
{ Purse thePurse = new Purse();
ConsoleReader console = new ConsoleReader(System.in);

Coin coin1 = new Coin(0.01, "pennies");


Coin coin2 = new Coin(0.05, "nickels");
Coin coin3 = new Coin(0.10, "dimes");
Coin coin4 = new Coin(0.25, "quarters");

System.out.println("How many " + coin1.getName()


+ " do you have?");
int coin1Count = console.readInt();

System.out.println("How many " + coin2.getName()


+ " do you have?");
int coin2Count = console.readInt();

System.out.println("How many " + coin3.getName()


+ " do you have?");
int coin3Count = console.readInt();

System.out.println("How many " + coin4.getName()


+ " do you have?");
int coin4Count = console.readInt();

thePurse.addCoins(coin1Count, coin1);
thePurse.addCoins(coin2Count, coin2);
thePurse.addCoins(coin3Count, coin3);
thePurse.addCoins(coin4Count, coin4);

System.out.println("The total value is $"


+ thePurse.getTotal());
}
}
What have you gained? The program composed of the three classes Coin, Purse,
and Coins6 looks quite a bit longer than the simple program in Chapter 2 that con-
sisted of a single class. That is true, and if you never had to write another program in
your life, you should certainly prefer the shorter version. However, the program that
is composed of multiple classes has two advantages. Once you have discovered the
concepts of coins and purses, you may be able to reuse these classes in other programs.
Further, by splitting the program into different classes, you can separate the responsi-
bilities of the various components, making the program easier to understand, easier
to implement correctly, and easier to extend. Note that the Purse class needs to know
124 Chapter 3. An Introduction to Classes

nothing about United States coin types (pennies, nickels, dimes, or quarters). You
could easily add a few pesos or Zorkmids to the purse.
Designing and implementing appropriate classes is an important part of writing
professional Java programs. It takes a bit longer to come up with the classes, and the
resulting programs are longer than programs that don’t use classes, but experience
has shown that such programs are more likely to be correct and are easier to maintain
over time. Those considerations are considerably more important in practice than
simply trying to write short programs quickly.

Productivity Hint 3.2


◆ Using the Command Line Effectively

◆ If your programming environment lets you accomplish all routine tasks with menus and dialog
◆ boxes, you can skip this note. However, if you need to invoke the editor, the compiler, the
◆ linker, and the program to test manually, then it is well worth learning about command line
◆ editing.
◆ Most operating systems (UNIX, DOS, OS/2) have a command line interface to interact with
◆ the computer. (In Windows, you can use the DOS command line interface by double-clicking
◆ the “MS-DOS Prompt” icon.) You launch commands at a prompt. The command is executed,
◆ and on completion you get another prompt.
◆ When you develop a program, you find yourself executing the same commands over and
◆ over. Wouldn’t it be nice if you didn’t have to type beastly commands like

◆ javac MyProg.java
◆ more than once? Or if you could fix a mistake rather than having to retype the command in its
◆ entirety? Many command line interfaces have an option to do just that, but they don’t always
◆ make it obvious. If you use DOS/Windows, you need to install a program called DOSKEY. If
◆ you use UNIX, try to get the tcsh shell installed for you, not the standard csh shell, and also be
◆ sure the history feature is activated—ask a lab assistant or system administrator to help you
◆ with the setup. With the proper setup, the up arrow keyq is redefined to cycle through your

old commands. You can edit lines with the left and right arrow keys. You can also perform

command completion. For example, to reissue the same javac command, type javac and press

F8 (DOS) or type !javac (UNIX).

Random Fact 3.1


◆ Mainframes–When Dinosaurs Ruled the Earth

When the International Business Machines Corporation, a successful manufacturer of punched-
◆ card equipment for tabulating data, first turned its attention to designing computers in the
◆ early 1950s, its planners assumed that there was a market for perhaps 50 such devices, for
◆ installation by the government, the military, and a few of the country’s largest corporations.
3.7 Discovering Classes 125


























◆ Figure 4


◆ A Mainframe Computer


◆ Instead, they sold about 1,500 machines of their System 650 model and went on to build and
◆ sell more powerful computers.
◆ The so-called mainframe computers of the 1950s, 1960s, and 1970s were huge. They filled
◆ up whole rooms, which had to be climate-controlled to protect the delicate equipment (see
◆ Figure 4). Today, because of miniaturization technology, even mainframes are getting smaller,
◆ but they are still very expensive. (At the time of this writing, the cost for a midrange IBM 3090
◆ is approximately 4 million dollars.)

These huge and expensive systems were an immediate success when they first appeared,

because they replaced many roomfuls of even more expensive employees, who had previously

performed the tasks by hand. Few of these computers do any exciting computations. They

◆ keep mundane information, such as billing records or airline reservations; they just keep lots
◆ of them.
◆ IBM was not the first company to build mainframe computers; that honor belongs to
◆ the Univac Corporation. However, IBM soon became the major player, partially because
◆ of technical excellence and attention to customer needs and partially because it exploited
◆ its strengths and structured its products and services in a way that made it difficult for cus-
◆ tomers to mix them with those of other vendors. In the 1960s IBM’s competitors, the so-called
◆ “Seven Dwarfs”—GE, RCA, Univac, Honeywell, Burroughs, Control Data, and NCR—fell
◆ on hard times. Some went out of the computer business altogether, while others tried
◆ unsuccessfully to combine their strengths by merging their computer operations. It was

126 Chapter 3. An Introduction to Classes

◆ generally predicted that they would eventually all fail. It was in this atmosphere that the
◆ U.S. government brought an antitrust suit against IBM in 1969. The suit went to trial in 1975
◆ and dragged on until 1982, when the Reagan Administration abandoned it, declaring it “with-
◆ out merit”.
◆ Of course, by then the computing landscape had changed completely. Just as the dino-
◆ saurs gave way to smaller, nimbler creatures, three new waves of computers had appeared:
◆ the minicomputers, workstations, and microcomputers, all engineered by new companies,

not the Seven Dwarfs. Today, the importance of mainframes in the marketplace has dimin-

ished, and IBM, while still a large and resourceful company, no longer dominates the com-

◆ puter market.
◆ Mainframes are still in use today for two reasons. They still excel at handling large data
◆ volumes. More importantly, the programs that control the business data have been refined
◆ over the last 20 or more years, fixing one problem at a time. Moving these programs to less
◆ expensive computers, with different languages and operating systems, is difficult and error-
◆ prone. Sun Microsystems, a leading manufacturer of workstations, was eager to prove that its
◆ mainframe system could be “downsized” and replaced by its own equipment. Sun eventually
◆ succeeded, but it took over five years—far longer than it expected.

3.8 Copying Object References

Consider the following code that copies a number and then adds an amount to the
copy:
double balance1 = 1000;
double balance2 = balance1; // see Figure 5
balance2 = balance2 + 500;

Of course, now balance1 is 1000, and balance2 is 1500.


Now consider the seemingly analogous code with BankAccount objects.
BankAccount account1 = new BankAccount(1000);
BankAccount account2 = account1; // see Figure 6
account2.deposit(500);

Unlike the preceding code, now both account1 and account2 have a balance of 1500.
In Java, there is a big difference between the assignment of numbers,
double balance2 = balance1;

and the assignment of objects


BankAccount account2 = account1;

Each number variable is a memory location that holds a value. If you change the
contents of either variable, then the other is not affected. Object variables, how-
ever, do not hold values; they hold references to objects. The actual object is stored
elsewhere, and the object variable remembers where it is stored. When you copy an
3.9 The null Reference 127

Figure 5 balance1 1000

balance2 1000
Copying Numbers

Figure 6 account1

account2
Copying Object Ref- BankAccount
erences
balance 1000

object variable, you do not make a copy of the object; you merely make a copy
of the reference. After the copy, both variables refer to the same object. If you
use a method that changes the object, then both variables access the changed ob-
ject.
What can you do if you actually need to make a true copy of an object, that is, a
new object whose state is identical to an existing object? As you will see in Chapter
9, you can define a clone method for your classes to make such a copy. But in the
meantime, you will simply have to construct a new object:
BankAccount account2 = new BankAccount(account1.getBalance());

3.9 The null Reference

An object variable contains a reference to an object. Unlike a number variable, an


object variable may refer to no object in particular. This special reference to no object
is called null. In the following code, account1 refers first to an object, then to no
object; see Figure 7.

Figure 7 account1 null

account2
A null Reference BankAccount

balance 1000
128 Chapter 3. An Introduction to Classes

BankAccount account1 = new BankAccount(1000);


BankAccount account2 = account1;
account1 = null;

If you try to invoke a method on a variable containing a null reference, the program
terminates. Clearly you must avoid doing so in your programs.
It is important to note that null is not the same as the number 0. The number 0
is a valid number, just like 1000 or ⫺13. A number variable always contains some
number. However, object variables have the choice between referring to an actual
object or referring to no object at all.
Unlike numbers, strings are objects in Java. A String variable can refer either to
an actual string or to no string at all:

String greeting = "Hello";


String message = ""; // the empty string
String comment = null; // refers to no string at all
int g = greeting.length(); // returns 5
int m = message.length(); // returns 0
int c = comment.length(); // program terminates

Note that the empty string and a null reference are different (see Figure 8), just as
there is a difference between an empty message (say, on an answering machine) and
no message at all (such as “no comment” by a spokesman for a politician).

Figure 8 greeting

message
String References String
comment null
"Hello"

String

""
3.9 The null Reference 129

Common Error 3.4


◆ Using a null Reference

◆ If an object variable is set to null, it does not refer to any object, and you cannot call any
◆ methods:

◆ BankAccount myAccount = null;
◆ myAccount.withdraw(100);
◆ // Error—cannot call methods on null reference

◆ When you execute code such as this, a NullPointerException is thrown, and your program
◆ terminates. You will learn in Chapter 5 how to test whether an object reference is null, so
◆ that you can avoid this error.
◆ Of course, the remedy is to make sure that the variable points to an actual object, not null,
◆ before you make a method call.

◆ BankAccount myAccount = new BankAccount();

Common Error 3.5


◆ Forgetting to Initialize Object References in a
◆ Constructor

◆ Just as it is a common error to forget to initialize a local variable, it is easy to forget about
◆ instance variables. Every constructor needs to ensure that all instance variables are set to ap-
◆ propriate values.
◆ If you do not initialize an instance variable, the Java compiler will initialize it for you.
◆ Numbers are initialized with 0, but object references—such as string variables—are set to the
◆ null reference! Of course, 0 is often a convenient default for numbers. However, null is
◆ hardly ever a convenient default for objects. Consider this “lazy” constructor for a modified
◆ BankAccount class:

◆ public class BankAccount
◆ { public BankAccount() {} // do nothing
◆ . . .
◆ private String accountHolder;
◆ private double balance;
◆ }

◆ The balance field is initialized to zero, a reasonable default. The accountHolder, however,
◆ is not set to the empty string; it is set to a null reference. If any method accesses that string
◆ assuming that it is a real string, the program will terminate with an error.
◆ If you forget to initialize a local variable in a method, the compiler flags this as an error, and
◆ you must fix it before the program runs. If you make the same mistake with an instance vari-
◆ able in a class, however, the compiler provides a default initialization, and the error becomes
130 Chapter 3. An Introduction to Classes

◆ apparent only when the program runs and dies with a null-reference error.
◆ To avoid this problem, make it a habit to initialize every instance variable in every con-
◆ structor.

Random Fact 3.2


◆ Computer Networks and the Internet

◆ Home computers and laptops are usually self-contained units with no permanent connection
◆ to other computers. Office and lab computers, however, are usually connected with each other
◆ and with larger computers: so-called servers. A server can store application programs and make
◆ them available on all computers on the network. Servers can also store data, such as schedules
◆ and mail messages, that everyone can retrieve. Networks that connect the computers in one
◆ building are called local area networks, or LANs.































◆ Figure 9


◆ A Web Browser


3.9 The null Reference 131

◆ Other networks connect computers in geographically dispersed locations. Such networks


◆ are called wide area networks or WANs. The most prominent wide area network is the Internet.
◆ At the time of this writing, the Internet is in a phase of explosive growth. Nobody knows for
◆ certain how many users have access to the Internet, but the user population is estimated in
◆ the hundreds of millions. The Internet grew out of the ARPAnet, a network of computers at
◆ universities that was funded by the Advanced Research Planning Agency of the U.S. Depart-
◆ ment of Defense. The original motivation behind the creation of the network was the desire
◆ to run programs on remote computers. Using remote execution, a researcher at one institution
◆ would be able to access an underutilized computer at a different site. It quickly became appar-
◆ ent, though, that remote execution was not what the network was actually used for. Instead,

the “killer application” was electronic mail: the transfer of messages between computer users at

different locations. To this day, electronic mail is one of the most compelling applications of

the Internet.

Over time, more and more information became available on the Internet. The information

◆ was created by researchers and hobbyists and made freely available to anyone, either out of
◆ the goodness of their hearts or for self-promotion. For example, the GNU (GNU’s Not UNIX)
◆ project is producing a set of high-quality operating system utilities and program development
◆ tools that can be used freely by anyone (ftp://prep.ai.mit.edu/pub/gnu). The Project
◆ Gutenberg makes available the text of important classical books, whose copyright has expired,
◆ in computer-readable form (http://www.gutenberg.org).
◆ The first interfaces to retrieve this information were clumsy and hard to use. All that
◆ changed with the appearance of the World Wide Web (WWW). The World Wide Web brought
◆ two major advances to Internet information. The information could contain graphics and
◆ fonts—a great improvement over the older text-only format—and it became possible to em-
◆ bed links to other information pages. Using a browser such as Netscape or Internet Explorer,
◆ surfing the Web becomes easy and fun (Figure 9).

Productivity Hint 3.3


◆ Save Your Work before Every
◆ Program Run

◆ You now have learned enough about programming that you can write programs that “hang”
◆ the computer—that is, run forever without giving you the chance of using the keyboard or
◆ the mouse again. Congratulations are in order.
◆ If you don’t save your work and your program hangs, you may be in a situation in which
◆ you must restart the computer and type it all again.
◆ You should therefore get into the habit of saving your work before every program run. Some
◆ integrated environments can be configured to do this automatically, but it is not always the
◆ default behavior. You can configure your fingers always to issue a “File Save All” command
◆ before running a program.
132 Chapter 3. An Introduction to Classes

3.10 Implementing the ConsoleReader


Class (Advanced)

In this section you will learn how to implement the ConsoleReader class that we use
for reading keyboard input in this book. If you are interested in the implementation
details, you should first read through Section 2.8 to understand the technical issues of
reading keyboard input in Java. If you aren’t interested in the implementation details
of the ConsoleReader class, you can safely skip this section.
A central aspect of class design is encapsulation: the hiding of unimportant details
from the class user. In Section 2.8 you saw how cumbersome it is in Java to read
a number from System.in: You must construct a BufferedReader, read a line of
input as a string, and convert it to a number, being careful about exceptions in the
process. That is just the kind of detail that lends itself to encapsulation.
To build the actual ConsoleReader class, let us use the same method as with the
BankAccount class:

1. Discover the behavior


2. Define the methods
3. Determine the instance variables for representing state
4. Implement the methods

Step 1: Let’s think of the behavior that you want for reading input. As the user of
the class, you are not particularly interested in buffered readers, number conversions,
or exceptions. You just want the value that the user is entering, converted to the right
type. Here is a set of methods that achieves this goal:

◆ Read an integer
◆ Read a floating-point number
◆ Read a string

Step 2: Translated to Java notation, the method and constructor definitions are as
follows:
public class ConsoleReader
{ public ConsoleReader(InputStream inStream)
{ constructor implementation
}
public int readInt()
{ method implementation
}
public double readDouble()
{ method implementation
}
public string readLine()
3.10 Implementing the ConsoleReader Class (Advanced) 133

{ method implementation
}

instance variables
}

Step 3: As you know from Section 2.8, you need a BufferedReader to read a
line of input. We will store that BufferedReader object in an instance variable of
the ConsoleReader class:
public class ConsoleReader
{ . . .
private BufferedReader reader;
}

This instance variable is set in the constructor. Recall from Section 2.8 that an input
stream can read only individual bytes. To read lines of characters, you must first turn
an input stream (such as system.in) into an input stream reader and then turn the
reader into a buffered reader
public class ConsoleReader
{ public ConsoleReader(InputStream inStream)
{ reader = new BufferedReader(new InputStreamReader(inStream));
}
. . .
}

Step 4: Now, let us turn to the implementation of the methods. We will first im-
plement the readLine method; it calls the readLine method of the reader object.
Now, though, we have to worry about exceptions. As we did in Chapter 2, we will
terminate the program when an I/O exception is encountered. Here is the code:
public String readLine()
{ String inputLine = "";

try
{ inputLine = reader.readLine();
}
catch(IOException e)
{ System.out.println(e);
System.exit(1);
}

return inputLine;
}
In other words, the readLine method of the ConsoleReader class simply calls the
readLine method of the BufferedReader class, and deals with the possibility of
the IOException, so that you don’t have to.
Having implemented this method, the other methods are very simple. To read
in an integer, simply read in an input line, using the readLine method that we just
134 Chapter 3. An Introduction to Classes

defined. Then parse the input into an integer and return that value. Floating-point
numbers are read in the same fashion.
public int readInt()
{ String inputString = readLine();
int n = Integer.parseInt(inputString);
return n;
}

public double readDouble()


{ String inputString = readLine();
double x = Double.parseDouble(inputString);
return x;
}
This completes the implementation of the ConsoleReader class.
When you look at the ConsoleReader.java file, you will find the method imple-
mentations that we just discussed. You will also find method comments. Those com-
ments will be explained in Chapter 6.

Chapter Summary

1. You use objects in your program when you need to manipulate data that are more
complex than just numbers and strings. Every object belongs to a class. A class de-
termines the behavior of its objects.

2. To define a class, you specify its methods and instance variables.

3. Every instance method has one implicit parameter—the object on which the
method is invoked—and zero or more explicit parameters.

4. Objects are constructed with the new operator, followed by a constructor.

5. Number variables hold values. Object variables hold references. When a number is
copied into a number variable, the variable gets a copy of the value. When an object is
copied into an object variable, the variable gets another reference to the same object.

6. The null reference refers to no object. Invoking a method on a null reference is


a fatal error.

Review Exercises

Exercise R3.1. Explain the difference between an object and a class.


Review Exercises 135

Exercise R3.2. Give the Java code for an object of class BankAccount and for an object
variable of class BankAccount.

Exercise R3.3. Explain the differences between an instance variable and a local vari-
able.

Exercise R3.4. Explain the difference between


new BankAccount(5000);
and
BankAccount b;

Exercise R3.5. What are the construction parameters for a BankAccount object?

Exercise R3.6. What is default construction?

Exercise R3.7. Give Java code to construct the following objects:

◆ A square with center (100, 100) and side length 25


◆ A bank account with a balance of $5000
◆ A console reader that reads from System.in

Write just objects, not object variables.

Exercise R3.8. Repeat the preceding exercise, but now define object variables that
are initialized with the required objects.

Exercise R3.9. Find the errors in the following statements:


Rectangle r = (5, 10, 15, 20);

double x = BankAccount(10000).getBalance();

BankAccount b;
b.deposit(10000);
b = new BankAccount(10000);
b.addCoins(new Coin(0.25, "quarters"));

Purse p = null;
p.addCoins(new Coin(0.25, "quarters"));

Purse p = new Purse();


p.addCoins(new Coin());

Exercise R3.10. Describe all constructors of the BankAccount class. List all methods
that can be used to change a BankAccount object. List all methods that don’t change
the BankAccount object.
136 Chapter 3. An Introduction to Classes

Exercise R3.11. What is the value of b after the following operations?


BankAccount b = new BankAccount(10);
b.deposit(5000);
b.withdraw(b.getBalance() / 2);

Exercise R3.12. If b1 and b2 store objects of class BankAccount, consider the fol-
lowing instructions.
b1.deposit(b2.getBalance());
b2.deposit(b1.getBalance());
Are the balances of b1 and b2 now identical? Explain.

Exercise R3.13. What is the this reference?

Programming Exercises

Exercise P3.1. Write a program that asks for an initial balance amount. Create a
BankAccount object with that amount. Then ask for a deposit amount and a with-
drawal amount. Carry out the deposit and withdrawal, then print the remaining bal-
ance.

Exercise P3.2. Implement a class Employee. An employee has a name (a string) and
a salary (a double). Write a default constructor, a constructor with two parameters
(name and salary), and methods to return the name and salary. Write a small program
that tests your class.

Exercise P3.3. Enhance the class in the preceding exercise by adding a method
raiseSalary(double byPercent) that raises the employee’s salary by a certain
percentage. Sample usage:
Employee harry = new Employee("Hacker, Harry", 55000);
harry.raiseSalary(10); // Harry gets a 10% raise

Exercise P3.4. Implement a class Car with the following properties. A car has a
certain fuel efficiency (measured in miles/gallon or liters/km—pick one) and a certain
amount of fuel in the gas tank. The efficiency is specified in the constructor, and the
initial fuel level is 0. Supply a method drive that simulates driving the car for a
certain distance, reducing the fuel level in the gas tank, and methods getFuelLevel,
returning the current fuel level, and tank, to tank up. Sample usage:
Car myBeemer = new Car(29); // 29 miles per gallon
myBeemer.tank(20); // tank 20 gallons
myBeemer.drive(100); // drive 100 miles
System.out.println(myBeemer.getFuelLevel());
// print fuel remaining
Programming Exercises 137

Exercise P3.5. Change the purse program Coins6 to ask the user to supply coins
in a different currency. For example, you can use the following collection of German
coins:
new Coin(0.01, "Pfennig");
new Coin(0.1, "Groschen");
new Coin(1.0, "Mark");
What changes did you have to make? What changes would you have to make to the
Coins4 program to change the currency? Which is easier?

Exercise P3.6. Add a method askForCoins(Coin coinType) to the Purse class


that asks the user how many coins of that type to add to the purse and that updates
the coin count.

Exercise P3.7. Implement a class Student. For the purpose of this exercise, a student
has a name and a total quiz score. Supply an appropriate constructor and methods
getName(), addQuiz(int score), getTotalScore(), and getAverageScore().
To compute the latter, you also need to store the number of quizzes that the student
took.

Exercise P3.8. Implement a class Product. A product has a name and a price, for
example new Product("Toaster", 29.95). Supply methods printProduct(),
getPrice(), and setPrice(). Write in a program that makes two products, prints
them, reduces their prices by $5.00, and then prints them again.

Exercise P3.9. Implement a class Circle that has methods getArea() and
getCircumference(). In the constructor, supply the radius of the circle.

Exercise P3.10. Implement a class BeerCan with methods getSurfaceArea() and


getVolume(). In the constructor, supply the height and radius of the can.

You might also like