Chapter 17
IN THIS CHAPTER
Programming with class (and with style and finesse)
Making objects from classes
Joining the exclusive “I understand classes and objects” society
Chapters 6, 7, and 8 introduce Java’s primitive types — things like int
, double
, char
, and boolean
. That’s great, but how often does a real-world problem deal exclusively with such simple values? Consider an exchange between a merchant and a customer. The customer makes a purchase, which can involve item names, model numbers, credit card info, sales tax rates, and lots of other stuff. A purchase is more complicated than an int
value. It’s more complicated than a double
value. How do you represent an entire purchase in a Java program?
In older computer programming languages, you treat an entire purchase like a big pile of unbundled laundry. Imagine a mound of socks, shirts, and other pieces of clothing. You have no basket, so you grab as much as you can handle. As you walk to the washer, you drop a few things — a sock here and a washcloth there. This is like the older way of storing the values in a purchase. In older languages, there’s no purchase. There are only double
values, char
values, and other loose items. You put the purchase amount in one variable, the customer’s name in another, and the sales tax data somewhere else. But that’s awful. You tend to drop things on your way to the compiler. With small errors in a program, you can easily drop an amount here and a customer’s name there.
With laundry and computer programming, you’re better off if you have a basket. The newer programming languages, like Java, allow you to combine values and make new, more useful kinds of values. For example, in Java, you can combine a double
value, an int
value, a boolean
value, and maybe other kinds of values to create something that you call a Purchase
. Because your purchase info is all in one big bundle, keeping track of the purchase’s pieces is easier. That’s the start of an important computer programming concept: the notion of object-oriented programming.
I start with a “traditional” example. The program in Listing 17-1 processes simple purchase data. A run of the program is shown in Figure 17-1.
LISTING 17-1 Doing It the Old-Fashioned Way
import java.util.Scanner;
class ProcessData {
public static void main(String args[]) {
Scanner keyboard = new Scanner(System.in);
double unitPrice;
int quantity;
boolean taxable;
System.out.print("Unit price: ");
unitPrice = keyboard.nextDouble();
System.out.print("Quantity: ");
quantity = keyboard.nextInt();
System.out.print("Taxable? (true/false) ");
taxable = keyboard.nextBoolean();
double total = unitPrice * quantity;
if (taxable) {
total = total * 1.05;
}
System.out.print("Total: ");
System.out.println(total);
keyboard.close();
}
}
If the output in Figure 17-1 looks funny, it’s because I do nothing in the code to control the number of digits beyond the decimal point. So in the output, the value $42.00 looks like 42.0
. That’s okay. I show you how to fix the problem in Chapter 18.
The code in Listing 17-1 involves a few simple values: unitPrice
, quantity
, and taxable
. So here’s the main point of this chapter: By combining several simple values, you can get a single, more useful value. That’s the way it works. You take some of Java’s primitive types, whip them together to make a primitive type stew, and what do you get? You get a more useful type called a reference type. Listing 17-2 has an example.
LISTING 17-2 What It Means to Be a Purchase
class Purchase {
double unitPrice;
int quantity;
boolean taxable;
}
The code in Listing 17-2 has no main
method, so Eclipse can compile the code, but you can’t run it. When you choose Run ⇒ Run As on Eclipse’s main menu, the resulting context menu has no Java Application entry. You can click the tiny Run As button in Eclipse’s toolbar and then select Java Application. But then you get the message box shown in Figure 17-2. Because Listing 17-2 has no main
method, there’s no place to start the executing. (In fact, the code in Listing 17-2 has no statements at all. There’s nothing to execute.)
To do something useful with the code in Listing 17-2, you need a main
method. You can put the main
method in a separate file. Listing 17-3 shows you such a file.
LISTING 17-3 Using Your Purchase Class
import java.util.Scanner;
class ProcessPurchase {
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
Purchase onePurchase = new Purchase();
System.out.print("Unit price: ");
onePurchase.unitPrice = keyboard.nextDouble();
System.out.print("Quantity: ");
onePurchase.quantity = keyboard.nextInt();
System.out.print("Taxable? (true/false) ");
onePurchase.taxable = keyboard.nextBoolean();
double total = onePurchase.unitPrice * onePurchase.quantity;
if (onePurchase.taxable) {
total = total * 1.05;
}
System.out.print("Total: ");
System.out.println(total);
keyboard.close();
}
}
The best way to understand the code in Listing 17-3 is to compare it, line by line, with the code in Listing 17-1. In fact, there’s a mechanical formula for turning the code in Listing 17-1 into the code in Listing 17-3. Table 17-1 describes the formula.
TABLE 17-1 Converting Your Code to Use a Class
In Listing 17-1 | In Listing 17-3 |
|
|
|
|
|
|
|
|
The two programs (in Listings 17-1 and 17-3) do essentially the same thing, but one uses primitive variables, and the other leans on the Purchase
code from Listing 17-2. Both programs have runs like the one shown back in Figure 17-1.
From Eclipse’s point of view, a project that contains two Java source files is no big deal. You create two classes in the same project, and then you choose Run ⇒ Run As ⇒ Java Application. Everything works the way you expect it to work.
The only time things become tricky is when you have two main
methods in the one project. This section’s example (refer to Listings 17-2 and 17-3) doesn’t suffer from that malady. But as you experiment with your code, you can easily add classes with additional main methods. You may also create a large application with several starting points.
When a project has more than one main
method, Eclipse may prompt you and ask which class’s main
method you want to run. But sometimes Eclipse doesn’t prompt you. Instead, Eclipse arbitrarily picks one main
method and ignores all the others. This can be very confusing. You add a println
call to the wrong main
method, and nothing appears in the Console view. Hey, what gives?
You can fix the problem by following these steps:
src
folder within the project’s branch.Expand the (default package)
branch within the src
branch.
The (default package)
branch contains .java
files.
.java
file whose main
method you want to run. (On a Mac) Control-click the .java
file whose main
method you want to run.On the surface, the code in Listing 17-3 is longer, more complicated, and harder to read. But think about a big pile of laundry: It may take time to find a basket and to shovel socks into the basket, but when you have clothes in the basket, the clothes are much easier to carry. It’s the same way with the code in Listing 17-3. When you have your data in a Purchase
basket, it’s much easier to do complicated things with purchases.
The code in Listing 17-2 defines a class. A class is a design plan; it describes the way in which you intend to combine and use pieces of data. For example, the code in Listing 17-2 announces your intention to combine double
, int
, and boolean
values to make new Purchase
values.
Classes are central to all Java programming. But Java is called an object-oriented language. Java isn’t called a class-oriented language. In fact, no one uses the term class-oriented language. Why not?
Well, you can’t put your arms around a class. A class isn’t real. A class without an object is like a day without chocolate. If you’re sitting in a room right now, glance at all the chairs in the room. How many chairs are in the room? Two? Five? Twenty? In a room with five chairs, you have five chair objects. Each chair (each object) is something real, something you can use, something you can sit on.
A language like Java has classes and objects. What’s the difference between a class and an object?
For example, how would you describe what a chair is? Well, a chair has a seat, a back, and legs. In Java, you may write the stuff in Listing 17-4.
LISTING 17-4 What It Means to Be a Chair
/*
* This is real Java code, but this code
* cannot be compiled on its own:
*/
class Chair {
FlatHorizonalPanel seat;
FlatVerticalPanel back;
LongSkinnyVerticalRods legs;
}
The code in Listing 17-4 is a design plan for chairs. The code tells you that each chair has three things. The code names the things (seat
, back
, and legs
) and tells you a little bit about each thing. (For example, a seat is a FlatHorizontalPanel
.) In the same way, the code in Listing 17-2 tells you that each purchase has three things. The code names the things (unitPrice
, quantity
, and taxable
) and tells you the primitive type of each thing.
Imagine some grand factory at the edge of the universe. While you sleep each night, this factory stamps out tangible objects — objects that you’ll encounter during the next waking day. Tomorrow you’ll go for an interview at the Sloshy Shoes Company. So tonight the factory builds chairs for the company’s offices. The factory builds chair objects, as shown in Figure 17-3, from the almost-real code in Listing 17-4.
In Listing 17-3, the line
Purchase onePurchase = new Purchase();
behaves like that grand factory at the edge of the universe. Rather than create chair objects, that line in Listing 17-3 creates a Purchase
object, as shown in Figure 17-4. That particular line in Listing 17-3 is a declaration with an initialization. Just as the line
int count = 0;
declares the count
variable and sets count
to 0, the line in Listing 17-3 declares the onePurchase
variable and makes onePurchase
point to a brand-new object. That new object contains three parts: an unitPrice
part, a quantity
part, and a taxable
part.
Sometimes, when you refer to a particular object, you want to emphasize which class the object came from. Well, subtle differences in emphasis call for big differences in terminology. So here’s how Java programmers use the terminology:
Purchase onePurchase = new Purchase()
creates a new object.Purchase onePurchase = new Purchase()
creates a new instance of the Purchase
class.The words object and instance are almost synonymous, but Java programmers never say “object of the Purchase
class” (or if they do, they feel funny).
By the way, if you mess up this terminology and say something like “object of the Purchase
class,” no one jumps down your throat. Everyone understands what you mean, and life goes on as usual. In fact, I often use a phrase like “Purchase
object” to describe an instance of the Purchase
class. The difference between object and instance isn’t terribly important. But it’s important to remember that the words object and instance have the same meaning. (Okay! They have nearly the same meaning.)
In the Purchase
code of Listing 17-2, I declare three variables: a unitPrice
variable, a quantity
variable, and a taxable
variable. In real-life, you might say that each purchase has three parts: the unitPrice of an item being purchased, the quantity of items purchased, and the fact that the purchase is or isn’t taxable.
When you create a Java class, each of these variables is called a field. The Purchase
class has three fields — namely, the unitPrice
field, the quantity
field, and the taxable
field.
After you’ve created an object, you use dots to refer to the object’s fields. For example, in Listing 17-3, I put a value into the onePurchase
object’s unitPrice
field with the following code:
onePurchase.unitPrice = keyboard.nextDouble();
Later in Listing 17-3, I get the unitPrice
field’s value with the following code:
double total = onePurchase.unitPrice * onePurchase.quantity;
This dot business may look cumbersome, but it really helps programmers when they’re trying to organize the code. In Listing 17-1, each variable is a separate entity. But in Listing 17-3, each use of the word unitPrice
is inextricably linked to the notion of a purchase. That’s good.
public static void main(String args[]) {
double amount;
amount = 5.95;
// … Etc.
One way or another, I don’t want you to get bogged down thinking about the words field and variable. A field is simply a variable that has a special role inside of a class. When I want to emphasize that special role, I use the word field. When I don’t want to emphasize that special role, I use the word variable. I may even switch back and forth between field and variable in the same sentence. Who knows? I might call something a fariable or a vield.
If you care about which word I use and when I use it, good for you. If you don’t care, don’t worry about it.
After you’ve created a Purchase
class, you can create as many purchase objects as you want. For example, in Listing 17-5, I create two purchase objects.
LISTING 17-5 Processing Purchases
class ProcessPurchases {
public static void main(String[] args) {
Purchase purchase1 = new Purchase();
purchase1.unitPrice = 20.00;
purchase1.quantity = 3;
purchase1.taxable = true;
Purchase purchase2 = new Purchase();
purchase2.unitPrice = 20.00;
purchase2.quantity = 3;
purchase2.taxable = false;
double purchase1Total = purchase1.unitPrice * purchase1.quantity;
if (purchase1.taxable) {
purchase1Total *= 1.05;
}
double purchase2Total = purchase2.unitPrice * purchase2.quantity;
if (purchase2.taxable) {
purchase2Total *= 1.05;
}
if (purchase1Total == purchase2Total) {
System.out.println("No difference");
} else {
System.out.println("These purchases have different totals.");
}
}
}
Figure 17-5 has a run of the code in Listing 17-5, and Figure 17-6 illustrates the concept.
Listing 17-5 has two purchase objects because the code
new Purchase();
is executed two times.
int count;
count = 0;
you can also separate a Purchase
variable’s assignment from the variable’s declaration:
Purchase purchase1;
purchase1 = new Purchase();
After you’ve created the code in Listing 17-2, the word Purchase
stands for a brand-new type — a reference type. Java has eight built-in primitive types and has as many reference types as people can define during your lifetime. In Listing 17-2, I define the Purchase
reference type, and you can define reference types, too.
Table 17-2 has a brief comparison of primitive types and reference types.
TABLE 17-2 Java Types
Primitive Type | Reference Type | |
How it’s created | Built into the language | Defined as a Java class |
How many are there | Eight | Indefinitely many |
Sample variable declaration |
|
|
Sample assignment |
|
|
Assigning a value to one of its parts | (Not applicable) |
|
When you start learning object-oriented programming, you may think that this class idea is a big hoax. Some geeks in Silicon Valley had nothing better to do, so they went to a bar and made up some confusing gibberish about classes. They don’t know what it means, but they have fun watching people struggle to understand it.
Well, that’s not what classes are all about. Classes are serious stuff. What’s more, classes are useful. Many reputable studies have shown that classes and object-oriented programming save time and money.
Even so, the notion of a class can be elusive. Even experienced programmers — the ones who are new to object-oriented programming — have trouble understanding how an object differs from a class.
Because classes can be mysterious, I’ll expand your understanding with another analogy. Figure 17-7 has a table of three purchases. The table’s title consists of one word (the word Purchase), and the table has three column headings: the words unitPrice, quantity, and taxable. Well, the code in Listing 17-2 has the same stuff — Purchase
, unitPrice
, quantity
, and taxable
. So in Figure 17-7, think of the top part of the table (the title and column headings) as a class. Like the code in Listing 17-2, this top part of the table tells you what it means to be a Purchase
. (It means having an unitPrice
value, a quantity
value, and a taxable
value.)
A class is like the top part of a table. And what about an object? Well, an object is like a row of a table. For example, with the code in Listing 17-5, I create two objects (two instances of the Purchase
class). The first object has unitPrice
value 20.00
, quantity
value 3
, and taxable
value true
. In the corresponding table, the first row has these three values — 20.00
, 3
, and true
, as shown in Figure 17-8.
Here’s the world’s briefest object-oriented programming FAQ:
Can I have an object without having a class?
No, you can’t. In Java, every object is an instance of a class.
Can I have a class without having an object?
Yes, you can. In fact, almost every program in this book creates a class without an object. Take Listing 17-5, for example. The code in Listing 17-5 defines a class named ProcessPurchases
. And nowhere in Listing 17-5 (or anywhere else) do I create an instance of the ProcessPurchases
class. I have a class with no objects. That’s just fine. It’s business as usual.
After I’ve created a class and its instances, can I add more instances to the class?
Yes, you can. In Listing 17-5, I create one instance and then another. In a for
loop, I could create a dozen instances and I’d have a dozen rows in the table of Figure 17-8. With no objects, three objects, four objects, or more objects, I still have the same old Purchase
class.
Can an object come from more than one class?
Bite your tongue! Maybe other object-oriented languages allow this nasty class cross-breeding, but in Java, it’s strictly forbidden. That’s one thing that distinguishes Java from some of the languages that preceded it: Java is cleaner, more uniform, and easier to understand.
Listing 17-5 contains some code that makes me nervous. In Listing 17-5, the statements that compute a purchase total appear once, and then appear a second time with only one tiny change:
double purchase1Total = purchase1.unitPrice * purchase1.quantity;
if (purchase1.taxable) {
purchase1Total *= 1.05;
}
double purchase2Total = purchase2.unitPrice * purchase2.quantity;
if (purchase2.taxable) {
purchase2Total *= 1.05;
}
To me, this repetition seems silly. Aren’t computers supposed to save us from mundane burdens such as repetitive typing? What if I type these statements correctly the first time, but make a mistake the second time? Maybe I’ll copy the bad version a third and fourth time and end up with code that’s all messed up!
Repetitive code is error-prone. It’s inconvenient and unnecessary. Instead of repeating code, you should be able to summarize your code and then refer to that summarized code repeatedly. With Java’s methods, you have precisely that capability. You’ve used other peoples’ methods in many examples throughout this book, and in Chapter 19, you create methods of your own.
A person’s body mass index (BMI) is the person’s weight (in kilograms) divided by the square of the person’s height (in meters). For example, a 65 kg person who’s 1.65 meters tall has a BMI of 23.875.
Person
class. Each Person
has a weight and a height. In other words, the Person
class has two fields: a weight
field (a double
value) and a height
field (another double
value).main
method. In the main
method, create a Person
object. Assign values to the Person
object’s weight
and height
fields by reading input from the keyboard. Use the Person
object’s weight
and height
fields to calculate the person’s BMI. Then output the person’s BMI.main
method that you wrote for the previous bullet so that it creates three Person
objects and calculates each object’s BMI.A country’s debt-to-GDP ratio is the amount of the government’s debt divided by the country’s gross domestic product (GDP). For example, a country with 14.3 trillion dollars of debt and 18.5 trillion dollars GDP has a debt-to-GDP ratio of approximately 77 percent. A low debt-to-GDP ratio means that a country can pay off its debts without having to incur even more debt.
Try writing the following code:
Country
class. Each Country
has a debt
and a gdp
. In other words, the Country
class has two fields: a debt
field (a double
value) and a gdp
field (another double
value).Create another class containing a main
method. In the main
method, create a Country
object. Assign values to the Country
object’s debt
and gdp
fields by reading input from the keyboard.
Also in the main
method, ask the user for an acceptable debt-to-GDP ratio. If your Country
object’s debt-to-GDP ratio is lower than the acceptable value, output the words That’s acceptable
. Otherwise, output That’s not acceptable
.
main
method that you wrote for the previous bullet so that it creates three Country
objects and displays That’s acceptable
or That’s not acceptable
for each object.This program isn’t about a Purchase
class, a Person
class, a Country
class, or about a class with any obvious real-world relevance:
Thing
class. The Thing
class has two fields: a value1
field (an int
value) and a value2
field (another int
value).main
method. In the main
method, create a Thing
object. Assign values to the Thing
object’s value1
and value2
fields by reading input from the keyboard. Use the Thing
object’s value1
and value2
fields to display a sentence about the object. A typical sentence might be
This thing has values 42 and 91.
main
method that you wrote for the previous bullet so that it creates three Thing
objects and displays a sentence about each of them.3.148.104.124