Chapter 7

Thinking in Terms of Classes and Objects

In This Chapter

arrow Thinking like a real object-oriented programmer

arrow Passing values to and from methods

arrow Hiding details in your object-oriented code

As a computer book author, I’ve been told this over and over again — I shouldn’t expect people to read sections and chapters in their logical order. People jump around, picking what they need and skipping what they don’t feel like reading. With that in mind, I realize that you may have skipped Chapter 1. If that’s the case, please don’t feel guilty. You can compensate in just 60 seconds by reading the following information culled from Chapter 1:

Because Java is an object-oriented programming language, your primary goal is to describe classes and objects. A class is the idea behind a certain kind of thing. An object is a concrete instance of a class. The programmer defines a class, and from the class definition, the computer makes individual objects.

Of course, you can certainly choose to skip over the 60-second summary paragraph. If that’s the case, you may want to recoup some of your losses. You can do that by reading the following two-word summary of Chapter 1:

Classes; objects.

Defining a Class (What It Means to Be an Account)

What distinguishes one bank account from another? If you ask a banker this question, you hear a long sales pitch. The banker describes interest rates, fees, penalties — the whole routine. Fortunately for you, I’m not interested in all that. Instead, I want to know how my account is different from your account. After all, my account is named Barry Burd, trading as Burd Brain Consulting, and your account is named Jane Q. Reader, trading as Budding Java Expert. My account has $24.02 in it. How about yours?

When you come right down to it, the differences between one account and another can be summarized as values of variables. Maybe there’s a variable named balance. For me, the value of balance is 24.02. For you, the value of balance is 55.63. The question is, when writing a computer program to deal with accounts, how do I separate my balance variable from your balance variable?

The answer is to create two separate objects. Let one balance variable live inside one of the objects and let the other balance variable live inside the other object. While you’re at it, put a name variable and an address variable in each of the objects. And there you have it — two objects, and each object represents an account. More precisely, each object is an instance of the Account class. (See Figure 7-1.)

9781118407806-fg0701.tif

Figure 7-1: Two objects.

So far, so good. However, you still haven’t solved the original problem. In your computer program, how do you refer to my balance variable, as opposed to your balance variable? Well, you have two objects sitting around, so maybe you have variables to refer to these two objects. Create one variable named myAccount and another variable named yourAccount. The myAccount variable refers to my object (my instance of the Account class) with all the stuff that’s inside it. To refer to my balance, write

  myAccount.balance

To refer to my name, write

  myAccount.name

Then yourAccount.balance refers to the value in your object’s balance variable, and yourAccount.name refers to the value of your object’s name variable. To tell the computer how much I have in my account, you can write

  myAccount.balance = 24.02;

To display your name on the screen, you can write

  out.println(yourAccount.name);

These ideas come together in Listings 7-1 and 7-2. Here's Listing 7-1:

Listing 7-1: What It Means to Be an Account

  public class Account {
   String name;
   String address;
   double balance;
}

The Account class in Listing 7-1 defines what it means to be an Account. In particular, Listing 7-1 tells you that each of the Account class’s instances has three variables — name, address, and balance. This is consistent with the information in Figure 7-1. Java programmers have a special name for variables of this kind (variables that belong to instances of classes). Each of these variables — name, address, and balance — is called a field.

remember.eps A variable declared inside a class but not inside any particular method is a field. In Listing 7-1, the variables name, address, and balance are fields. Another name for a field is an instance variable.

If you’ve been grappling with the material in Chapters 4 through 6, the code for class Account (Listing 7-1) may come as a big shock to you. Can you really define a complete Java class with only four lines of code (give or take a curly brace)? You certainly can. In fact, the Account class in Listing 7-1 is quite representative of what Java programmers think of when they think class. A class is a grouping of existing things. In the Account class of Listing 7-1, those existing things are two String values and a double value.

Declaring variables and creating objects

A young fellow approaches me while I'm walking down the street. He tells me to print “You'll love Java!” so I print those words. If you must know, I print them with chalk on the sidewalk. But where I print the words doesn't matter. What matters is that some guy issues instructions, and I follow the instructions.

Later that day, an elderly woman sits next to me on a park bench. She says, “An account has a name, an address, and a balance.” And I say, “That's fine, but what do you want me to do about it?” In response she just stares at me, so I don't do anything about her account pronouncement. I just sit there, she sits there, and we both do absolutely nothing.

Listing 7-1, shown earlier, is like the elderly woman. This listing defines what it means to be an Account, but the listing doesn't tell me to do anything with my account, or with anyone else's account. In order to do something, I need a second piece of code. I need another class — a class that contains a main method. Fortunately, while the woman and I sit quietly on the park bench, a young child comes by with Listing 7-2.

Listing 7-2: Dealing with Account Objects

  import static java.lang.System.out;

public class UseAccount {

   public static void main(String args[]) {
      Account myAccount;
      Account yourAccount;

      myAccount = new Account();
      yourAccount = new Account();

      myAccount.name = "Barry Burd";
      myAccount.address = "222 Cyberspace Lane";
      myAccount.balance = 24.02;

      yourAccount.name = "Jane Q. Public";
      yourAccount.address = "111 Consumer Street";
      yourAccount.balance = 55.63;

      out.print(myAccount.name);
      out.print(" (");
      out.print(myAccount.address);
      out.print(") has $");
      out.print(myAccount.balance);
      out.println();

      out.print(yourAccount.name);
      out.print(" (");
      out.print(yourAccount.address);
      out.print(") has $");
      out.print(yourAccount.balance);
   }
}

Taken together, the two classes — Account and UseAccount — form one complete program. The code in Listing 7-2 defines the UseAccount class, and the UseAccount class has a main method. This main method has variables of its own — yourAccount and myAccount.

In a way, the first two lines inside the main method of Listing 7-2 are misleading. Some people read Account yourAccount as if it’s supposed to mean, “yourAccount is an Account,” or “The variable yourAccount refers to an instance of the Account class.” That’s not really what this first line means. Instead, the line Account yourAccount means, “If and when I make the variable yourAccount refer to something, that something will be an instance of the Account class.” So, what’s the difference?

The difference is that simply declaring Account yourAccount doesn’t make the yourAccount variable refer to an object. All the declaration does is reserve the variable name yourAccount so that the name can eventually refer to an instance of the Account class. The creation of an actual object doesn’t come until later in the code, when the computer executes new Account().

cross-reference.eps Technically, when the computer executes new Account(), you’re creating an object by calling the Account class’s constructor. I have more to say about that in Chapter 9.

When the computer executes the assignment yourAccount = new Account(), the computer creates a new object (a new instance of the Account class) and makes the variable yourAccount refer to that new object. (The equal sign makes the variable refer to the new object.) Figure 7-2 illustrates the situation.

9781118407806-fg0702.tif

Figure 7-2: Before and after a constructor is called.

To test the claim that I made in the last few paragraphs, I added an extra line to the code of Listing 7-2. I tried to print yourAccount.name after declaring yourAccount but before calling new Account().

     Account myAccount;
   Account yourAccount;
    
   out.println(yourAccount.name);

   myAccount = new Account();
   yourAccount = new Account();  

When I tried to compile the new code, I got this error message: variable yourAccount might not have been initialized. That settles it. Before you do new Account(), you can’t print the name variable of an object because an object doesn’t exist.

remember.eps When a variable has a reference type, simply declaring the variable isn’t enough. You don’t get an object until you call a constructor and use the keyword new.

For information about reference types, see Chapter 4.

Initializing a variable

In Chapter 4, I announce that you can initialize a primitive type variable as part of the variable’s declaration.

  int weightOfAPerson = 150;

You can do the same thing with reference type variables, such as myAccount and yourAccount in Listing 7-2. You can combine the first four lines in the listing’s main method into just two lines, like this:

  Account myAccount = new Account();
Account yourAccount = new Account();

If you combine lines this way, you automatically avoid the variable might not have been initialized error that I describe in the previous section. Sometimes you find a situation in which you can’t initialize a variable. But when you can initialize, it’s usually a plus.

Using an object’s fields

After you’ve bitten off and chewed the main method’s first four lines, the rest of the code in the earlier Listing 7-2 is sensible and straightforward. You have three lines that put values in the myAccount object’s fields, three lines that put values in the yourAccount object’s fields, and four lines that do some printing. Figure 7-3 shows the program’s output.

9781118407806-fg0703.tif

Figure 7-3: Running the code in Listings 2-7 and 1-4.

One program; several classes

Each program in Chapters 3 to 6 consists of a single class. That’s great for a book’s introductory chapters. But in real life, a typical program consists of hundreds or even thousands of classes. The program that spans Listings 2-7 and 1-4 consists of two classes. Sure, having two classes isn’t like having thousands of classes, but it’s a step in that direction.

In practice, most programmers put each class in a file of its own. When you create a program, such as the one in Listings 2-7 and 1-4, you create two files on your computer’s hard drive. Therefore, when you download this section's example from the web, you get two separate files — Account.java and UseAccount.java.

ontheweb_fmt.eps For information about running a program consisting of more than one .java file in Eclipse, NetBeans and IntelliJ IDEA, visit this book's website (www.allmycode.com/JavaForDummies).

Public classes

The first line of Listing 7-1 is

  public class Account {

The Account class is public. A public class is available for use by all other classes. For example, if you write an ATMController program in some remote corner of cyberspace, then your ATMController program can contain code, such as myAccount.balance = 24.02, making use of the Account class declared in Listing 7-1. (Of course, your code has to know where in cyberspace I've stored the code in Listing 7-1, but that's another story.)

Listing 7-2 contains the code myAccount.balance = 24.02. You might say to yourself, “The Account class has to be public because another class (the code in Listing 7-2) uses the Account class.” Unfortunately, the real lowdown about public classes is a bit more complicated. In fact, when the planets align themselves correctly, one class can make use of another class's code, even though the other class isn't public. (I cover the proper aligning of planets in Chapter 14.)

The dirty secret in this chapter's code is that declaring certain classes to be public simply makes me feel good. Yes, programmers do certain things to feel good. In Listing 7-1, my esthetic sense of goodness comes from the fact that an Account class is useful to many other programmers. When I create a class that declares something useful and nameable — an Account, an Engine, a Customer, a BrainWave, a Headache, or a SevenLayerCake class — I declare the class to be public.

The UseAccount class in Listing 7-2 is also public. When a class contains a main method, Java programmers tend to make the class public without thinking too much about who uses the class. So even if no other class makes use of my main method, I declare the UseAccount class to be public. Most of the classes in this book contain main methods, so most of the classes in this book are public.

warning.eps When you declare a class to be public, you must declare the class in a file whose name is exactly the same as the name of the class (but with the .java extension added). For example, if you declare public class MyImportantCode, you must put the class's code in a file named MyImportantCode.java, with uppercase letters M, I, and C and all other letters lowercase. This file-naming rule has an important consequence: If your code declares two public classes, your code must consist of at least two .java files. In other words, you can't declare two public classes in one .java file.

For more news about the word public and other such words, see Chapter 14.

Defining a Method within a Class (Displaying an Account)

Imagine a table containing the information about two accounts. (If you have trouble imagining such a thing, just look at Table 7-1.)

Table 7-1 Without Object-Oriented Programming

Name

Address

Balance

Barry Burd

222 Cyberspace Lane

24.02

Jane Q. Public

111 Consumer Street

55.63

In Table 7-1, each account has three things — a name, an address, and a balance. That’s how things were done before object-oriented programming came along. But object-oriented programming involved a big shift in thinking. With object-oriented programming, each account can have a name, an address, a balance, and a way of being displayed.

In object-oriented programming, each object has its own built-in functionality. An account knows how to display itself. A string can tell you whether it has the same characters inside it as another string has. A PrintStream instance, such as System.out, knows how to do println. In object-oriented programming, each object has its own methods. These methods are little subprograms that you can call to have an object do things to (or for) itself.

And why is this a good idea? It’s good because you’re making pieces of data take responsibility for themselves. With object-oriented programming, all the functionality that’s associated with an account is collected inside the code for the Account class. Everything you have to know about a string is located in the file String.java. Anything having to do with year numbers (whether they have two or four digits, for instance) is handled right inside the Year class. Therefore, if anybody has problems with your Account class or your Year class, he or she knows just where to look for all the code. That’s great!

So imagine an enhanced account table. In this new table, each object has built-in functionality. Each account knows how to display itself on the screen. Each row of the table has its own copy of a display method. Of course, you don’t need much imagination to picture this table. I just happen to have a table you can look at. It’s Table 7-2.

0702

An account that displays itself

In Table 7-2, each account object has four things — a name, an address, a balance, and a way of displaying itself on the screen. After you make the jump to object-oriented thinking, you’ll never turn back. Listings 2-7 and 3-4 show programs that implement the ideas in Table 7-2.

Listing 7-3: An Account Displays Itself

  import static java.lang.System.out;

public class Account {
   String name;
   String address;
   double balance;

   public void display() {
      out.print(name);
      out.print(" (");
      out.print(address);
      out.print(") has $");
      out.print(balance);
   }
}

Listing 7-4: Using the Improved Account Class

  public class UseAccount {

   public static void main(String args[]) {
      Account myAccount = new Account();
      Account yourAccount = new Account();

      myAccount.name = "Barry Burd";
      myAccount.address = "222 Cyberspace Lane";
      myAccount.balance = 24.02;

      yourAccount.name = "Jane Q. Public";
      yourAccount.address = "111 Consumer Street";
      yourAccount.balance = 55.63;

      myAccount.display();
      System.out.println();
      yourAccount.display();
   }
}

A run of the code in Listings 2-7 and 3-4 looks just like a run for Listings 2-7 and 1-4. You can see the action back in Figure 7-3.

In Listing 7-3, the Account class has four things in it — a name, an address, a balance, and a display method. These things match up with the four columns in Table 7-2. So each instance of the Account class has a name, an address, a balance, and a way of displaying itself. The way you call these things is nice and uniform. To refer to the name stored in myAccount, you write

  myAccount.name

To get myAccount to display itself on the screen, you write

  myAccount.display()

The only difference is the parentheses.

remember.eps When you call a method, you put parentheses after the method’s name.

The display method’s header

Look again at Listings 2-7 and 3-4. A call to the display method is inside the UseAccount class’s main method, but the declaration of the display method is up in the Account class. The declaration has a header and a body. (See Chapter 3.) The header has three words and some parentheses:

  • The word public serves roughly the same purpose as the word public in Listing 7-1. Roughly speaking, any code can contain a call to a public method, even if the calling code and the public method belong to two different classes. In this section's example, the decision to make the display method public is a matter of taste. Normally, when I create a method that's useful in a wide variety of applications, I declare the method to be public.
  • The word void tells the computer that when the display method is called, the display method doesn’t return anything to the place that called it. To see a method that does return something to the place that called it, see the next section.
  • The word display is the method’s name. Every method must have a name. Otherwise, you don’t have a way to call the method.
  • The parentheses contain all the things you’re going to pass to the method when you call it. When you call a method, you can pass information to that method on the fly. The display method in Listing 7-3 looks strange because the parentheses in the method’s header have nothing inside them. This nothingness indicates that no information is passed to the display method when you call it. For a meatier example, see the next section.

cross-reference.eps Listing 7-3 contains the display method's declaration, and Listing 7-4 contains a call to the display method. Although Listings 2-7 and 3-4 contain different classes, both uses of public in Listing 7-3 are optional. To find out why, check out Chapter 14.

Sending Values to and from Methods (Calculating Interest)

Think about sending someone to the supermarket to buy bread. When you do this, you say, “Go to the supermarket and buy some bread.” (Try it at home. You’ll have a fresh loaf of bread in no time at all!) Of course, some other time, you send that same person to the supermarket to buy bananas. You say, “Go to the supermarket and buy some bananas.” And what’s the point of all this? Well, you have a method, and you have some on-the-fly information that you pass to the method when you call it. The method is named goToTheSupermarketAndBuySome. The on-the-fly information is either bread or bananas, depending on your culinary needs. In Java, the method calls would look like this:

  goToTheSupermarketAndBuySome(bread);
goToTheSupermarketAndBuySome(bananas);

The things in parentheses are called parameters or parameter lists. With parameters, your methods become much more versatile. Instead of getting the same thing each time, you can send somebody to the supermarket to buy bread one time, bananas another time, and birdseed the third time. When you call your goToTheSupermarketAndBuySome method, you decide right there what you’re going to ask your pal to buy.

And what happens when your friend returns from the supermarket? “Here’s the bread you asked me to buy,” says your friend. By carrying out your wishes, your friend returns something to you. You make a method call, and the method returns information (or a loaf of bread).

The thing returned to you is called the method’s return value. The general type of thing that is returned to you is called the method’s return type. These concepts are made more concrete in Listings 2-7 and 5-4.

Listing 7-5: An Account That Calculates Its Own Interest

  import static java.lang.System.out;

public class Account {
   String name;
   String address;
   double balance;

   public void display() {
      out.print(name);
      out.print(" (");
      out.print(address);
      out.print(") has $");
      out.print(balance);
   }

   public double getInterest(double percentageRate) {
      return balance * percentageRate / 100.00;
   }
}

Listing 7-6: Calculating Interest

  import static java.lang.System.out;

public class UseAccount {

   public static void main(String args[]) {
      Account myAccount = new Account();
      Account yourAccount = new Account();

      myAccount.name = "Barry Burd";
      myAccount.address = "222 Cyberspace Lane";
      myAccount.balance = 24.02;

      yourAccount.name = "Jane Q. Public";
      yourAccount.address = "111 Consumer Street";
      yourAccount.balance = 55.63;

      myAccount.display();
      
      out.print(" plus $");
      out.print(myAccount.getInterest(5.00));
      out.println(" interest ");

      yourAccount.display();
      
      double yourInterestRate = 7.00;       
      out.print(" plus $");
      double yourInterestAmount =
         yourAccount.getInterest(yourInterestRate);
      out.print(yourInterestAmount);
      out.println(" interest ");
   }
}

Figure 7-4 shows the output of the code in Listings 2-7 and 5-4. In Listing 7-5, the Account class has a getInterest method. This getInterest method is called twice from the main method in Listing 7-6. The actual account balances and interest rates are different each time.

9781118407806-fg0704.tif

Figure 7-4: Running the code in Listings 2-7 and 5-4.

  • In the first call, the balance is 24.02, and the interest rate is 5.00. The first call, myAccount.getInterest(5.00), refers to the myAccount object and to the values stored in the myAccount object's fields. (See Figure 7-5.) When this call is made, the expression balance * percentageRate / 100.00 stands for 24.02 * 5.00 / 100.00.
  • In the second call, the balance is 55.63, and the interest rate is 7.00. In the main method, just before this second call is made, the variable yourInterestRate is assigned the value 7.00. The call itself, yourAccount.getInterest(yourInterestRate), refers to the yourAccount object and to the values stored in the yourAccount object's fields. (Again, see Figure 7-5.) So, when the call is made, the expression balance * percentageRate / 100.00 stands for 55.63 * 7.00 / 100.00.
    9781118407806-fg0705.tif

    Figure 7-5: My account and your account.

By the way, the main method in Listing 7-3 contains two calls to getInterest. One call has the literal 5.00 in its parameter list; the other call has the variable yourInterestRate in its parameter list. Why does one call use a literal and the other call use a variable? No reason. I just want to show you that you can do it either way.

Passing a value to a method

Take a look at the getInterest method’s header. (As you read the explanation in the next few bullets, you can follow some of the ideas visually with the diagram in Figure 7-6.)

9781118407806-fg0706.tif

Figure 7-6: Passing a value to a method.

  • The word double tells the computer that when the getInterest method is called, the getInterest method returns a double value back to the place that called it. The statement in the getInterest method’s body confirms this. The statement says return balance * 
percentageRate / 100.00, and the expression balance * percentageRate / 100.00 has type double. (That’s because all the things in the expression — balance, percentageRate, and 100.00 — have type double.)

    When the getInterest method is called, the return statement calculates balance * percentageRate / 100.00 and hands the calculation’s result back to the code that called the method.

  • The word getInterest is the method’s name. That’s the name you use to call the method when you’re writing the code for the UseAccount class.
  • The parentheses contain all the things that you pass to the method when you call it. When you call a method, you can pass information to that method on the fly. This information is the method’s parameter list. The getInterest method’s header says that the getInterest method takes one piece of information and that piece of information must be of type double.

      public double getInterest(double percentageRate)

    Sure enough, if you look at the first call to getInterest (down in the useAccount class’s main method), that call has the number 5.00 in it. And 5.00 is a double literal. When I call getInterest, I’m giving the method a value of type double.

    cross-reference.eps If you don’t remember what a literal is, see Chapter 4.

    The same story holds true for the second call to getInterest. Down near the bottom of Listing 7-6, I call getInterest and feed the variable yourInterestRate to the method in its parameter list. Luckily for me, I declared yourInterestRate to be of type double just a few lines before that.

When you run the code in Listings 2-7 and 5-4, the flow of action isn’t from top to bottom. The action goes from main to getInterest, then back to main, then back to getInterest, and finally back to main again. Figure 7-7 shows the whole business.

9781118407806-fg0707.tif

Figure 7-7: The flow of control in Listings 2-7 and 5-4.

Returning a value from the getInterest method

When the getInterest method is called, the method executes the one statement that’s in the method’s body: a return statement. The return statement computes the value of balance * percentageRate / 100.00. If balance happens to be 24.02, and percentageRate is 5.00, the value of the expression is 1.201 — around $1.20. (Because the computer works exclusively with 0s and 1s, the computer gets this number wrong by an ever so tiny amount. The computer gets 1.2009999999999998. That’s just something that humans have to live with.)

Anyway, after this value is calculated, the computer executes the return, which sends the value back to the place in main where getInterest was called. At that point in the process, the entire method call — myAccount.getInterest(5.00) — takes on the value 1.2009999999999998. The call itself is inside a println:

  out.println(myAccount.getInterest(5.00));

So the println ends up with the following meaning:

  out.println(1.2009999999999998);

The whole process, in which a value is passed back to the method call, is illustrated in Figure 7-8.

9781118407806-fg0708.tif

Figure 7-8: A method call is an expression with a value.

remember.eps If a method returns anything, a call to the method is an expression with a value. That value can be printed, assigned to a variable, added to something else, or whatever. Anything you can do with any other kind of value, you can do with a method call.

ontheweb_fmt.eps You might use the Account class in Listing 7-5 to solve a real problem. You'd call the Account class's display and getInterest methods in the course of an actual banking application. But the UseAccount class in Listing 7-6 is artificial. The UseAccount code creates some fake account data and then calls some Account class methods to convince you that the Account class's code works correctly. (You don't seriously think that a bank has depositors named “Jane Q. Public” and “Barry Burd,” do you?) The UseAccount class in Listing 7-6 is a test case — a short-lived class whose sole purpose is to test another class's code. Like the code in Listing 7-6, each test case in this book is an ordinary class — a free-form class containing its own main method. Free-form classes are okay, but they're not optimal. Java developers have something better — a more disciplined way of writing test cases. The “better way” is called JUnit, and it's described on this book's website (www.allmycode.com/JavaForDummies).

Making Numbers Look Good

Looking back at Figure 7-4, you may be concerned that the interest on my account is only $1.2009999999999998. Seemingly, the bank is cheating me out of two hundred-trillionths of a cent. I should go straight there and demand my fair interest. Maybe you and I should go together. We’ll kick up some fur at that old bank and bust this scam right open. If my guess is correct, this is part of a big salami scam. In a salami scam, someone shaves little slices off millions of accounts. People don’t notice their tiny little losses, but the person doing the shaving collects enough for a quick escape to Barbados (or for a whole truckload of salami).

But, wait a minute! Nothing is motivating you to come with me to the bank. Checking back at Figure 7-4, I see that you’re way ahead of the game. According to my calculations, the program overpays you by three hundred-trillionths of a cent. Between the two of us, we’re ahead by a hundred-trillionth of a cent. What gives?

Well, because computers use 0s (zeros) and 1s and don’t have an infinite amount of space to do calculations, such inaccuracies as the ones shown in Figure 7-4 are normal. The quickest solution is to display the inaccurate numbers in a more sensible fashion. You can round the numbers and display only two digits beyond the decimal point, and some handy tools from Java’s API (Application Programming Interface) can help. Listing 7-7 shows the code, and Figure 7-9 displays the pleasant result.

Listing 7-7: Making Your Numbers Look Right

  import static java.lang.System.out;

public class UseAccount {

   public static void main(String args[]) {
      Account myAccount = new Account();
      Account yourAccount = new Account();

      myAccount.balance = 24.02;
      yourAccount.balance = 55.63;

      double myInterest = myAccount.getInterest(5.00);
      double yourInterest = 
yourAccount.getInterest(7.00);

      out.printf("$%4.2f ", myInterest);
      out.printf("$%5.2f ", myInterest);
      out.printf("$%.2f ", myInterest);
      out.printf("$%3.2f ", myInterest);
      out.printf("$%.2f $%.2f",
                       myInterest, yourInterest);
   }
}

9781118407806-fg0709.tif

Figure 7-9: Numbers that look like dollar amounts.

ontheweb_fmt.eps The inaccurate numbers in Figure 7-4 come from the computer's use of 0s and 1s. A mythical computer whose circuits were wired to use digits 0, 1, 2, 3, 4, 5, 6, 7, 8, and 9 wouldn't suffer from the same inaccuracies. So to make things better, Java provides its own special way around the computer's inaccurate calculations. Java's API has a class named BigDecimal — a class that bypasses the computer's strange 0s and 1s, and uses ordinary decimal digits to perform arithmetic calculations. For more information, visit this book's website (www.allmycode.com/JavaForDummies).

Listing 7-7 uses a handy method named printf. When you call printf, you always put at least two parameters inside the call’s parentheses.

  • The first parameter is a format string.

    The format string uses funny-looking codes to describe exactly how the other parameters are displayed.

  • All the other parameters (after the first) are values to be displayed.

Look at the last printf call of Listing 7-7. The first parameter’s format string has two placeholders for numbers. The first placeholder (%.2f) describes the display of myInterest. The second placeholder (another %.2f) describes the display of yourInterest. To find out exactly how these format strings work, see Figures 7-10 through 7-14.

9781118407806-fg0710.tif

Figure 7-10: Using a format string.

9781118407806-fg0711.tif

Figure 7-11: Adding extra places to display a value.

9781118407806-fg0712.tif

Figure 7-12: Displaying a value without specifying the exact number of places.

9781118407806-fg0713.tif

Figure 7-13: Specifying too few places to display a value.

9781118407806-fg0714.tif

Figure 7-14: Displaying more than one value with a format string.

For more examples using the printf method and its format strings, see Chapters 8 and 9. For a complete list of options associated with the printf method’s format string, see the java.util.Formatter page of Java’s API documentation.

remember.eps The format string in a printf call doesn’t change the way a number is stored internally for calculations. All the format string does is create a nice-looking bunch of digit characters that can be displayed on your screen.

Hiding Details with Accessor Methods

Put down this book and put on your hat. You’ve been such a loyal reader that I’m taking you out to lunch!

I have just one problem. I’m a bit short on cash. Would you mind if, on the way to lunch, we stopped at an automatic teller machine and picked up a few bucks? Also, we have to use your account. My account is a little low.

Fortunately, the teller machine is easy to use. Just step right up and enter your PIN. After entering your PIN, the machine asks which of several variable names you want to use for your current balance. You have a choice of balance324, myBal, currentBalance, b$, BALANCE, asj999, or conStanTinople. Having selected a variable name, you’re ready to select a memory location for the variable’s value. You can select any number between 022FFF and 0555AA. (Those numbers are in hexadecimal format.) After you configure the teller machine’s software, you can easily get your cash. You did bring a screwdriver, didn’t you?

Good programming

When it comes to good computer programming practice, one word stands out above all others — simplicity. When you’re writing complicated code, the last thing you want is to deal with somebody else’s misnamed variables, convoluted solutions to problems, or clever, last-minute kludges. You want a clean interface that makes you solve your own problems and no one else’s.

In the automatic teller machine scenario that I describe earlier, the big problem is that the machine’s design forces you to worry about other people’s concerns. When you should be thinking about getting money for lunch, you’re thinking instead about variables and storage locations. Sure, someone has to work out the teller machine’s engineering problems, but the banking customer isn’t the person.

remember.eps This section is about safety, not security. Safe code keeps you from making accidental programming errors. Secure code (a completely different story) keeps malicious hackers from doing intentional damage.

So, everything connected with every aspect of a computer program has to be simple, right? Well, no. That’s not right. Sometimes, to make things simple in the long run, you have to do lots of preparatory work up front. The people who built the automated teller machine worked hard to make sure that the machine is consumer-proof. The machine’s interface, with its screen messages and buttons, makes the machine a very complicated, but carefully designed, device.

The point is that making things look simple takes some planning. In the case of object-oriented programming, one of the ways to make things look simple is to prevent code outside a class from directly using fields defined inside the class. Take a peek at the code in Listing 7-1. You’re working at a company that has just spent $10 million for the code in the Account class. (That’s more than a million and a half per line!) Now your job is to write the UseAccount class. You would like to write

  myAccount.name = "Barry Burd";

but doing so would be getting you too far inside the guts of the Account class. After all, people who use an automatic teller machine aren’t allowed to program the machine’s variables. They can’t use the machine’s keypad to type the statement

  balanceOnAccount29872865457 =
   balanceOnAccount29872865457 + 1000000.00;

Instead, they push buttons that do the job in an orderly manner. That’s how a programmer achieves safety and simplicity.

So, to keep things nice and orderly, you need to change the Account class from Listing 7-1 by outlawing such statements as the following:

  myAccount.name = "Barry Burd";

and

  out.print(yourAccount.balance);

Of course, this poses a problem. You’re the person who’s writing the code for the UseAccount class. If you can’t write myAccount.name or yourAccount.balance, how are you going to accomplish anything at all? The answer lies in things called accessor methods. Listings 2-7 and 8-4 demonstrate these methods.

Listing 7-8: Hide Those Fields

  public class Account {
   private String name;
   private String address;
   private double balance;

   public void setName(String n) {
      name = n;
   }

   public String getName() {
      return name;
   }

   public void setAddress(String a) {
      address = a;
   }

   public String getAddress() {
      return address;
   }

   public void setBalance(double b) {
      balance = b;
   }

   public double getBalance() {
      return balance;
   }
}

Listing 7-9: Calling Accessor Methods

  import static java.lang.System.out;

public class UseAccount {

   public static void main(String args[]) {
      Account myAccount = new Account();
      Account yourAccount = new Account();

      myAccount.setName("Barry Burd");
      myAccount.setAddress("222 Cyberspace Lane");
      myAccount.setBalance(24.02);

      yourAccount.setName("Jane Q. Public");
      yourAccount.setAddress("111 Consumer Street");
      yourAccount.setBalance(55.63);

      out.print(myAccount.getName());
      out.print(" (");
      out.print(myAccount.getAddress());
      out.print(") has $");
      out.print(myAccount.getBalance());
      out.println();

      out.print(yourAccount.getName());
      out.print(" (");
      out.print(yourAccount.getAddress());
      out.print(") has $");
      out.print(yourAccount.getBalance());
   }
}

A run of the code in Listings 2-7 and 8-4 looks no different from a run of Listings 2-7 and 1-4. Either program’s run is shown back in Figure 7-3. The big difference is that in Listing 7-8, the Account class enforces the carefully controlled use of its name, address, and balance fields.

Public lives and private dreams: Making a field inaccessible

Notice the addition of the word private in front of each of the Account class’s field declarations. The word private is a Java keyword. When a field is declared private, no code outside of the class can make direct reference to that field. So if you put myAccount.name = "Barry Burd" in the UseAccount class of Listing 7-9, you get the error message name has private access in Account.

Instead of referencing myAccount.name, the UseAccount programmer must call method myAccount.setName or method myAccount.getName. These methods, setName and getName, are called accessor methods because they provide access to the Account class’s name field. (Actually, the term accessor method isn’t formally a part of the Java programming language. It’s just the term that people use for methods that do this sort of thing.) To zoom in even more, setName is called a setter method, and getName is called a getter method. (I bet you won’t forget that terminology!)

tip.eps With many IDEs, you don’t have to type your own accessor methods. First, you type a field declaration like private String name. Then, in your IDE's menu bar, you choose Source➪Generate Getters and Setters, or choose Code➪Insert Code➪Setter or some mix of those commands. After you make all your choices, the IDE creates accessor methods and adds them to your code.

Notice that all the setter and getter methods in Listing 7-8 are declared to be public. This ensures that anyone from anywhere can call these two methods. The idea here is that manipulating the actual fields from outside the Account code is impossible, but you can easily reach the approved setter and getter methods for using those fields.

Think again about the automatic teller machine. Someone using the ATM can’t type a command that directly changes the value in his or her account’s balance field, but the procedure for depositing a million-dollar check is easy to follow. The people who build the teller machines know that if the check depositing procedure is complicated, plenty of customers will mess it up royally. So that’s the story — make impossible anything that people shouldn’t do and make sure that the tasks people should be doing are easy.

tip.eps Nothing about having setter and getter methods is sacred. You don’t have to write any setter and getter methods that you’re not going to use. For instance, in Listing 7-8, I can omit the declaration of method getAddress, and everything still works. The only problem if I do this is that anyone else who wants to use my Account class and retrieve the address of an existing account is up a creek.

tip.eps When you create a method to set the value in a balance field, you don’t have to name your method setBalance. You can name it tunaFish or whatever you like. The trouble is that the setFieldname convention (with lowercase letters in set and an uppercase letter to start the Fieldname part) is an established stylistic convention in the world of Java programming. If you don’t follow the convention, you confuse the kumquats out of other Java programmers. If your integrated development environment has drag-and-drop GUI design capability, you may temporarily lose that capability. (For a word about drag-and-drop GUI design, see Chapters 2 and 15.)

remember.eps When you call a setter method, you feed it a value of the type that’s being set. That’s why, in Listing 7-9, you call yourAccount.setBalance(55.63) with a parameter of type double. In contrast, when you call a getter method, you usually don’t feed any values to the method. That’s why, in Listing 7-9, you call yourAccount.getBalance() with an empty parameter list. Occasionally, you may want to get and set a value with a single statement. To add a dollar to your account’s existing balance, you write yourAccount.setBalance(yourAccount.getBalance() + 1.00).

Enforcing rules with accessor methods

Go back to Listing 7-8 and take a quick look at the setName method. Imagine putting the method’s assignment statement inside an if statement.

  public void setName(String n) {
   if (!n.equals("")) {
      name = n;
   }
}

Now, if the programmer in charge of the UseAccount class writes myAccount.
setName(""), the call to setName doesn’t have any effect. Furthermore, because the name field is private, the following statement is illegal in the UseAccount class:

  myAccount.name = "";

Of course, a call such as myAccount.setName("Joe Schmoe") still works because "Joe Schmoe" doesn’t equal the empty string "".

That’s cool. With a private field and an accessor method, you can prevent someone from assigning the empty string to an account’s name field. With more elaborate if statements, you can enforce any rules you want.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.70.185