Chapter 10

Putting Variables and Methods Where They Belong

In This Chapter

arrow Making something belong to an entire class

arrow Putting variables inside and outside methods

arrow Improving your batting average

Hello, again. You’re listening to radio station WWW, and I’m your host, Sam Burd. It’s the start again of the big baseball season, and today station WWW brought you live coverage of the Hankees versus Socks game. At this moment, I’m awaiting news of the game’s final score.

If you remember from earlier this afternoon, the Socks looked like they were going to take those Hankees to the cleaners. Then, the Hankees were belting ball after ball, giving the Socks a run for their money. Those Socks! I’m glad I wasn’t in their shoes.

Anyway, as the game went on, the Socks pulled themselves up. Now the Socks are nose to nose with the Hankees. We’ll get the final score in a minute, but first, a few reminders. Stay tuned after this broadcast for the big Jersey’s game. And don’t forget to tune in next week when the Cleveland Gowns play the Bermuda Shorts.

Okay, here’s the final score. Which team has the upper hand? Which team will come out a head? And the winner is … oh, no! It’s a tie!

Defining a Class (What It Means to Be a Baseball Player)

As far as I’m concerned, a baseball player has a name and a batting average. Listing 10-1 puts my feeling about this into Java program form.

Listing 10-1: The Player Class

  import java.text.DecimalFormat;

public class Player {  
   private String name;
   private double average;

   public Player(String name, double average) {
      this.name=name;
      this.average=average;
   }

   public String getName() {
      return name;
   }

   public double getAverage() {
      return average;
   }

   public String getAverageString() {
      DecimalFormat decFormat = new DecimalFormat();
      decFormat.setMaximumIntegerDigits(0);
      decFormat.setMaximumFractionDigits(3);
      decFormat.setMinimumFractionDigits(3);
      return decFormat.format(average);   
   }
}

So here I go, picking apart the code in Listing 10-1. Luckily, earlier chapters cover lots of stuff in this code. The code defines what it means to be an instance of the Player class. Here’s what’s in the code:

  • Declarations of the fields name and average: For bedtime reading about field declarations, see Chapter 7.
  • A constructor to make new instances of the Player class: For the lowdown on constructors, see Chapter 9.
  • Getter methods for the fields name and average: For chitchat about accessor methods (that is, setter and getter methods), see Chapter 7.
  • A method that returns the player’s batting average in String form: For the good word about methods, see Chapter 7. (I put a lot of good stuff in Chapter 7, didn’t I?)

Another way to beautify your numbers

The getAverageString method in Listing 10-1 takes the value from the average field (a player’s batting average), converts that value (normally of type double) into a String, and then sends that String value right back to the method caller. The use of DecimalFormat, which comes right from the Java API (Application Programming Interface), makes sure that the String value looks like a baseball player’s batting average. According to the decFormat.setMaximum... and decFormat.setMinimum... method calls, the String value has no digits to the left of the decimal point and has exactly three digits to the right of the decimal point.

Java’s DecimalFormat class can be quite handy. For example, to display the values 345 and –345 with an accounting-friendly format, you can use the following code:

  DecimalFormat decFormat = new DecimalFormat();
decFormat.setMinimumFractionDigits(2);
decFormat.setNegativePrefix("(");
decFormat.setNegativeSuffix(")");
System.out.println(decFormat.format(345));
System.out.println(decFormat.format(-345));

In this little example’s format string, everything before the semicolon dictates the way positive numbers are displayed, and everything after the semicolon determines the way negative numbers are displayed. So with this format, the numbers 345 and –345 appear as follows:

  345.00
(345.00)

To discover some other tricks with numbers, visit the DecimalFormat page of Java’s API documentation.

Using the Player class

Listings 2-10 and 2-4 have code that uses the Player class — the class that's defined back in Listing 10-1.

Listing 10-2: Using the Player Class

  import java.util.Scanner;
import java.io.File;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.JLabel;
import java.awt.GridLayout;

@SuppressWarnings("serial")
public class TeamFrame extends JFrame {

   public TeamFrame() throws IOException {
      Player player;
      Scanner hankeesData =
               new Scanner(new File("Hankees.txt"));

      for (int num = 1; num <= 9; num++) {
         player = new Player(hankeesData.nextLine(),
                        hankeesData.nextDouble());
         hankeesData.nextLine();
                   
         addPlayerInfo(player);
      }      

      setTitle("The Hankees");
      setLayout(new GridLayout(9, 2, 20, 3));
      setDefaultCloseOperation(EXIT_ON_CLOSE);
      pack();
      setVisible(true);

      hankeesData.close();
   }
    
   void addPlayerInfo(Player player) {
      add(new JLabel(" " + player.getName()));
      add(new JLabel(player.getAverageString()));
   }  
}

Listing 10-3: Displaying a Frame

  import java.io.IOException;

public class ShowTeamFrame {

   public static void main(String args[])
                       throws IOException {
      new TeamFrame();
   }
}

For a run of the code in Listings 10-1, 10-2, and 10-3, see Figure 10-1.

9781118407806-fg1001.tif

Figure 10-1: Would you bet money on these people?

To run this program yourself, you need the Hankees.txt file. This file contains data on your favorite baseball players. (See Figure 10-2.)

9781118407806-fg1002.tif

Figure 10-2: What a team!

ontheweb_fmt.eps You don't have to create your own Hankees.txt file. The stuff that you download from this book's website comes with a Hankees.txt file as shown in Figure 10-2. (Visit www.allmycode.com/JavaForDummies.)

You must have the Hankees.txt file in a certain place on your hard drive. If you’re using Eclipse, that “certain place” is a project directory within your Eclipse workspace. On the other hand, if you’re running Java from the command line, that “place” may be the directory that contains the Listing 10-3 code. One way or another, you can’t get away without having the Hankees.txt file in the right place on your hard drive. If you don’t have Hankees.txt in the right place, then when you try to run this section’s example, you'll get an unpleasant FileNotFoundException message.

ontheweb_fmt.eps When you download stuff from this book's website, you get instructions for importing the download into your favorite IDE (Eclipse, NetBeans, or IntelliJ IDEA). The import process puts the Hankees.txt file exactly where it needs to be. You don't have to worry about putting the file where it belongs.

If you create this section's example from scratch, you have to think about the correct location of the Hankees.txt file. In that case, deciding where to put the Hankees.txt file depends on your computer. To read about all these things, visit this book’s website (www.allmycode.com/JavaForDummies).

remember.eps For this section’s code to work correctly, you must have a line break after the last .212 in Figure 10-2. For details about line breaks, see Chapter 8.

Nine, count ’em, nine

The code in Listing 10-2 calls the Player constructor nine times. This means that the code creates nine instances of the Player class. The first time through the loop, the code creates an instance with the name Barry Burd. The second time through the loop, the code abandons the Barry Burd instance and creates another instance with name Harriet Ritter. The third time through, the code abandons poor Harriet Ritter and creates an instance for Weelie J. Katz. The code has only one instance at a time but, all in all, the code creates nine instances.

Each Player instance has its own name and average fields. Each instance also has its own Player constructor and its own getName, getAverage, and getAverageString methods. Look at Figure 10-3 and think of the Player class with its nine incarnations.

9781118407806-fg1003.tif

Figure 10-3: A class and its objects.

Don’t get all GUI on me

The code in Listing 10-2 uses several names from the Java API. Some of these names are explained in Chapter 9. Others are explained right here:

  • JLabel: A JLabel is an object with some text in it. One of the ways to display text inside the frame is to add an instance of the JLabel class to the frame.

    In Listing 10-2, the addPlayerInfo method is called nine times, once for each player on the team. Each time addPlayerInfo is called, the method adds two new JLabel objects to the frame. The text for each JLabel object comes from a player object’s getter method.

  • GridLayout: A GridLayout arranges things in evenly spaced rows and columns. This constructor for the GridLayout class takes two parameters: the number of rows and the number of columns.

    In Listing 10-2, the call to the GridLayout constructor takes parameters (9, 2, 20, 3). So in Figure 10-1, the display has nine rows (one for each player) and two columns (one for a name and another for an average). The horizontal gap between the two columns is 20 pixels wide, and the vertical gap between any two rows is 3 pixels tall.

  • pack: When you pack a frame, you set the frame’s size. That’s the size the frame has when it appears on your computer screen. Packing a frame shrink-wraps the frame around whatever objects you’ve added inside the frame.

    In Listing 10-2, by the time you’ve reached the call to pack, you’ve already called addPlayerInfo nine times and added 18 labels to the frame. In executing the pack method, the computer picks a nice size for each label, given whatever text you’ve put inside the label. Then, the computer picks a nice size for the whole frame, given that the frame has these 18 labels inside it.

When you plop stuff onto frames, you have quite a bit of leeway with the order in which you do things. For instance, you can set the layout before or after you’ve added labels and other stuff to the frame. If you call setLayout and then add labels, the labels appear in nice, orderly positions on the frame. If you reverse this order (add labels and then call setLayout), the calling of setLayout rearranges the labels in a nice, orderly fashion. It works fine either way.

In setting up a frame, the one thing that you shouldn’t do is violate the following sequence:

  Add things to the frame, then
pack();
setVisible(true);

If you call pack and then add more things to the frame, the pack method doesn’t take the more recent things that you’ve added into consideration. If you call setVisible before you add things or call pack, the user sees the frame as it’s being constructed. Finally, if you forget to set the frame’s size (by calling pack or some other sizing method), the frame that you see looks like the one in Figure 10-4. (Normally, I wouldn’t show you an anomalous run like the one in Figure 10-4, but I’ve made the mistake so many times that I feel as if this puny frame is an old friend of mine.)

9781118407806-fg1004.tif

Figure 10-4: An undernourished frame.

Tossing an exception from method to method

Chapter 8 introduces input from a disk file, and along with that topic comes the notion of an exception. When you tinker with a disk file, you need to acknowledge the possibility of raising an IOException. That’s the lesson from Chapter 8, and that’s why the constructor in Listing 10-2 has a throws IOException clause.

But what about the main method in Listing 10-3? With no apparent reference to disk files in this main method, why does the method need its own throws IOException clause? Well, an exception is a hot potato. If you have one, you either have to eat it (as you can see in Chapter 13) or use a throws clause to toss it to someone else. If you toss an exception with a throws clause, someone else is stuck with the exception just the way you were.

The constructor in Listing 10-2 throws an IOException, but to whom is this exception thrown? Who in this chain of code becomes the bearer of responsibility for the problematic IOException? Well, who called the constructor in Listing 10-2? It was the main method in Listing 10-3 — that’s who called the TeamFrame constructor. Because the TeamFrame constructor throws its hot potato to the main method in Listing 10-3, the main method has to deal with it. As shown in Listing 10-3, the main method deals with it by tossing the IOException again (by having a throws IOException clause of its own). That’s how the throws clause works in Java programs.

remember.eps If a method calls another method and the called method has a throws clause, the calling method must contain code that deals with the exception. To find out more about dealing with exceptions, read Chapter 13.

technicalstuff.eps At this point in the book, the astute For Dummies reader may pose a follow-up question or two. “When a main method has a throws clause, someone else has to deal with the exception in that throws clause. But who called the main method? Who deals with the IOException in the throws clause of Listing 10-3?” The answer is that the Java Virtual Machine (or JVM, the thing that runs all your Java code) called the main method. So the JVM takes care of the IOException in Listing 10-3. If the program has any trouble reading the Hankees.txt file, the responsibility ultimately falls on the JVM. The JVM takes care of things by displaying an error message and then ending the run of your program. How convenient!

Making Static (Finding the Team Average)

Thinking about the code in Listings 10-1 through 10-3, you decide that you’d like to find the team’s overall batting average. Not a bad idea! The Hankees in Figure 10-1 have an average of about .106, so the team needs some intensive training. While the players are out practicing on the ball field, you have a philosophical hurdle to overcome.

In Listings 10-1 through 10-3, you have three classes: a Player class and two other classes that help display data from the Player class. So in this class morass, where do the variables storing your overall, team-average tally go?

  • It makes no sense to put tally variables in either of the displaying classes (TeamFrame and ShowTeamFrame). After all, the tally has something or other to do with players, teams, and baseball. The displaying classes are about creating windows, not about playing baseball.
  • You’re uncomfortable putting an overall team average in an instance of the Player class because an instance of the Player class represents just one player on the team. What business does a single player have storing overall team data? Sure, you could make the code work, but it wouldn’t be an elegant solution to the problem.

Finally, you discover the keyword static. Anything that’s declared to be static belongs to the whole class, not to any particular instance of the class. When you create the static field, totalOfAverages, you create just one copy of the field. This copy stays with the entire Players class. No matter how many instances of the Player class you create — one, nine, or none — you have just one totalOfAverages field. And, while you’re at it, you create other static fields (playerCount and decFormat) and static methods (findTeamAverage and findTeamAverageString). To see what I mean, look at Figure 10-5.

9781118407806-fg1005.tif

Figure 10-5: Some static and non-static fields and methods.

Going along with your passion for subclasses, you put code for team-wide tallies in a subclass of the Player class. The code is shown in Listing 10-4.

Listing 10-4: Creating a Team Batting Average

  import java.text.DecimalFormat;

public class PlayerPlus extends Player {
   private static int playerCount = 0;
   private static double totalOfAverages = .000;
   private static DecimalFormat decFormat =
                          new DecimalFormat();

   static {
      decFormat.setMaximumIntegerDigits(0);
      decFormat.setMaximumFractionDigits(3);
      decFormat.setMinimumFractionDigits(3);
   }

   public PlayerPlus(String name, double average) {
      super(name, average);
      playerCount++;
      totalOfAverages += average;
   }

   public static double findTeamAverage() {
      return totalOfAverages / playerCount;
   }

   public static String findTeamAverageString() {
      return decFormat.format
                 (totalOfAverages / playerCount);
   }
}

Why is there so much static?

Maybe you’ve noticed — the code in Listing 10-4 is overflowing with the word static. That’s because nearly everything in this code belongs to the entire PlayerPlus class and not to individual instances of the class. That’s good because something like playerCount (the number of players on the team) shouldn’t belong to individual players, and having each PlayerPlus object keep track of its own count would be silly. (“I know how many players I am. I’m just one player!”) If you had nine individual playerCount fields, either each field would store the number 1 (which is useless) or you would have nine different copies of the count, which is wasteful and prone to error. So by making playerCount static, you’re keeping the playerCount in just one place, where it belongs.

The same kind of reasoning holds for the totalOfAverages. Eventually, the totalOfAverages field will store the sum of the players’ batting averages. For all nine members of the Hankees, this adds up to .956. It’s not until someone calls the findTeamAverage or findTeamAverageString method that the computer actually finds the overall Hankee team batting average.

You also want the methods findTeamAverage and findTeamAverage
String to be static. Without the word static, there would be nine find
TeamAverage methods — one for each instance of the PlayerPlus class. This wouldn’t make much sense. Each instance would have the code to calculate totalOfAverages/playerCount on its own, and each of the nine calculations would yield the very same answer.

In general, any task that all the instances have in common (and that yields the same result for each instance) should be coded as a static method.

remember.eps Constructors are never static.

Meet the static initializer

In Listing 10-4, the decFormat field is static. This makes sense, because decFormat makes totalOfAverages / playerCount look nice, and both fields in the expression totalOfAverages / playerCount are static. Thinking more directly, the code needs only one thing for formatting numbers. If you have several numbers to format, the same decFormat thing that belongs to the entire class can format each number. Creating a decFormat for each player is not only inelegant, but also wasteful.

But declaring decFormat to be static presents a little problem. To set up the formatting, you have to call methods like decFormat.setMaximum
IntegerDigits(0). You can’t just plop these method calls anywhere in the PlayerPlus class. For example, the following code is bad, invalid, illegal, and otherwise un-Java-like:

  // THIS IS BAD CODE:
public class PlayerPlus extends Player {
   private static DecimalFormat decFormat =
                          new DecimalFormat();

   decFormat.setMaximumIntegerDigits(0);   // Bad!
   decFormat.setMaximumFractionDigits(3);  // Bad!
   decFormat.setMinimumFractionDigits(3);  // Bad!

Look at the examples from previous chapters. In those examples, I never let a method call just dangle on its own, the way I do in the bad, bad code. In this chapter, in Listing 10-1, I don’t call setMaximumIntegerDigits without putting the method call inside the getAverageString method’s body. This no-dangling-method-calls business isn't an accident. Java’s rules restrict the places in the code where you can issue calls to methods, and putting a lonely method call on its own immediately inside a class definition is a big no-no.

So in Listing 10-4, where can you put the necessary setMax and setMin calls? You can put them inside the body of the findTeamAverageString method, much the way I put them inside the getAverageString method in Listing 10-1. But putting those method calls inside the findTeamAverageString method’s body might defeat the purpose of having decFormat be static. After all, a programmer might call findTeamAverageString several times, calling decFormat.setMaximumIntegerDigits(0) each time. But that would be very wasteful. The entire PlayerPlus class has only one decFormat field, and that decFormat field’s MaximumIntegerDigits value is always 0. So don’t keep setting MaximumIntegerDigits(0) over and over again.

The best alternative is to take the bad lines in this section’s bad code and put them inside a static initializer. Then they become good lines inside good code. (See Listing 10-4.) A static initializer is a block that’s preceded by the word static. Java executes the static initializer’s statements once for the entire class. That's exactly what you want for something called “static.”

Displaying the overall team average

You may be noticing a pattern. When you create code for a class, you generally write two pieces of code. One piece of code defines the class, and the other piece of code uses the class. (The ways to use a class include calling the class’s constructor, referencing the class’s non-private fields, calling the class’s methods, and so on.) Listing 10-4, shown previously, contains code that defines the PlayerPlus class, and Listing 10-5 contains code that uses this PlayerPlus class.

Listing 10-5: Using the Code from Listing 10-4

  import java.util.Scanner;
import java.io.File;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.JLabel;
import java.awt.GridLayout;

@SuppressWarnings("serial")
public class TeamFrame extends JFrame {

   public TeamFrame() throws IOException {
      PlayerPlus player;
      Scanner hankeesData =
               new Scanner(new File("Hankees.txt"));

      for (int num = 1; num <= 9; num++) {
         player =
           new PlayerPlus(hankeesData.nextLine(),
                       hankeesData.nextDouble());
         hankeesData.nextLine();
                   
         addPlayerInfo(player);
      }      
      
      add(new JLabel());
      add(new JLabel(" ------"));
      add(new JLabel("Team Batting Average:"));
      add(new JLabel(PlayerPlus.findTeamAverageString()));

      setTitle("The Hankees");
      setLayout(new GridLayout(11, 2, 20, 3));
      setDefaultCloseOperation(EXIT_ON_CLOSE);
      pack();
      setVisible(true);

      hankeesData.close();
   }
    
   void addPlayerInfo(PlayerPlus player) {
      add(new JLabel(" " + player.getName()));
      add(new JLabel(player.getAverageString()));
   }  
}

To run the code in Listing 10-5, you need a class with a main method. The ShowTeamFrame class in Listing 10-3 works just fine.

Figure 10-6 shows a run of the code from Listing 10-5. This run depends on the availability of the Hankees.txt file from Figure 10-2. The code in Listing 10-5 is almost an exact copy of the code from Listing 10-2. (So close is the copy that if I could afford it, I’d sue myself for theft of intellectual property.) The only thing new in Listing 10-5 is the stuff shown in bold.

9781118407806-fg1006.tif

Figure 10-6: A run of the code in Listing 10-5.

In Listing 10-5, the GridLayout has two extra rows: one row for spacing and another row for the Hankee team’s average. Each of these rows has two Label objects in it.

  • The spacing row has a blank label and a label with a dashed line. The blank label is a placeholder. When you add components to a GridLayout, the components are added row by row, starting at the left end of a row and working toward the right end. Without this blank label, the dashed line label would appear at the left end of the row, under Hugh R. DaReader’s name.
  • The other row has a label displaying the words Team Batting Average, and another label displaying the number .106. The method call that gets the number .106 is interesting. The call looks like this:

      PlayerPlus.findTeamAverageString()

    Take a look at that method call. That call has the following form:

      ClassName.methodName()

    That’s new and different. In earlier chapters, I say that you normally preface a method call with an object’s name, not a class’s name. So why do I use a class name here? The answer: When you call a static method, you preface the method’s name with the name of the class that contains the method. The same holds true whenever you reference another class’s static field. This makes sense. Remember, the whole class that defines a static field or method owns that field or method. So, to refer to a static field or method, you preface the field or method’s name with the class’s name.

tip.eps When you’re referring to a static field or method, you can cheat and use an object’s name in place of the class name. For instance, in Listing 10-5, with judicious rearranging of some other statements, you can use the expression player.findTeamAverageString().

Static is old hat

This section makes a big noise about static fields and methods, but static things have been part of the picture since early in this book. For example, Chapter 3 introduces System.out.println. The name System refers to a class, and out is a static field in that class. That’s why, in Chapter 4 and beyond, I use the static keyword to import the out field:

  import static java.lang.System.out;

In Java, static fields and methods show up all over the place. When they’re declared in someone else’s code, and you’re making use of them in your code, you hardly ever have to worry about them. But when you’re declaring your own fields and methods and must decide whether to make them static, you have to think a little harder.

technicalstuff.eps In this book, my first serious use of the word static is way back in Listing 3-1. I use the static keyword as part of every main method (and lots of main methods are in this book’s listings). So why does main have to be static? Well, remember that non-static things belong to objects, not classes. If the main method isn’t static, you can’t have a main method until you create an object. But, when you start up a Java program, no objects have been created yet. The statements that are executed in the main method start creating objects. So, if the main method isn’t static, you have a big chicken-and-egg problem.

Could cause static; handle with care

When I first started writing Java, I had recurring dreams about getting a certain error message. The message was non-static variable or method cannot be referenced from a static context. So often did I see this message, so thoroughly was I perplexed, that the memory of this message became burned into my subconscious existence.

These days, I know why I got that error message so often. I can even make the message occur if I want. But I still feel a little shiver whenever I see this message on my screen.

Before you can understand why the message occurs and how to fix the problem, you need to get some terminology under your belt. If a field or method isn’t static, it’s called non-static. (Real surprising, hey?) Given that terminology, there are at least two ways to make the dreaded message appear:

  • Put Class.nonstaticThing somewhere in your program.
  • Put nonstaticThing somewhere inside a static method.

In either case, you’re getting yourself into trouble. You’re taking something that belongs to an object (the non-static thing) and putting it in a place where no objects are in sight.

Take, for instance, the first of the two situations I just described. To see this calamity in action, go back to Listing 10-5. Toward the end of the listing, change player.getName() to Player.getName(). That does the trick. What could Player.getName possibly mean? If anything, the expression Player.getName means “call the getName method that belongs to the entire Player class.” But look back at Listing 10-1. The getName method isn’t static. Each instance of the Player (or PlayerPlus) class has a getName method. None of the getName methods belong to the entire class. So the call Player.getName doesn’t make any sense. (Maybe the computer is pulling punches when it displays the inoffensive cannot be referenced ... message. Perhaps a harsh nonsensical expression message would be more fitting.)

For a taste of the second situation (in the bullet list that I give earlier in this section), go back to Listing 10-4. While no one’s looking, quietly remove the word static from the declaration of the decFormat field (near the top of the listing). This removal turns decFormat into a non-static field. Suddenly, each player on the team has a separate decFormat field.

Well, things are just hunky-dory until the computer reaches the findTeam
AverageString method. That static method has four decFormat.SuchAndSuch statements in it. Once again, you’re forced to ask what a statement of this kind could possibly mean. Method findTeamAverageString belongs to no instance in particular. (The method is static, so the entire PlayerPlus class has one findTeamAverageString method.) But with the way you’ve just butchered the code, plain old decFormat without reference to a particular object has no meaning. So again, you’re referencing the non-static field, decFormat, from inside a static method’s context. For shame, for shame, for shame!

Experiments with Variables

One summer during my college days, I was sitting on the front porch, loafing around, talking with someone I’d just met. I think her name was Janine. “Where are you from?” I asked. “Mars,” she answered. She paused to see whether I’d ask a follow-up question.

As it turned out, Janine was from Mars, Pennsylvania, a small town about 20 miles north of Pittsburgh. Okay, so what’s my point? The point is that the meaning of a name depends on the context. If you’re just north of Pittsburgh and ask, “How do I get to Mars from here?” you may get a sensible, nonchalant answer. But if you ask the same question standing on a street corner in Manhattan, you’ll probably arouse some suspicion. (Okay, knowing Manhattan, people would probably just ignore you.)

Of course, the people who live in Mars, Pennsylvania, are very much aware that their town has an oddball name. Fond memories of teenage years at Mars High School don’t prevent a person from knowing about the big red planet. On a clear evening in August, you can still have the following conversation with one of the local residents:

  • You: How do I get to Mars?
  • Local resident: You’re in Mars, pal. What particular part of Mars are you looking for?
  • You: No, I don’t mean Mars, Pennsylvania. I mean the planet Mars.
  • Local resident: Oh, the planet! Well, then, catch the 8:19 train leaving for Cape Canaveral … No, wait, that’s the local train. That’d take you through West Virginia… .

So the meaning of a name depends on where you’re using the name. Although most English-speaking people think of Mars as a place with a carbon dioxide atmosphere, some folks in Pennsylvania think about all the shopping they can do in Mars. And those folks in Pennsylvania really have two meanings for the name Mars. In Java, those names may look like this: Mars and planets.Mars.

Putting a variable in its place

Your first experiment is shown in Listings 2-10 and 6-4. The listings’ code highlights the difference between variables that are declared inside and outside methods.

Listing 10-6: Two Meanings for Mars

  import static java.lang.System.out;

class EnglishSpeakingWorld {
   String mars = "  red planet";

   void visitPennsylvania() {
      out.println("visitPA is running:");

      String mars = "  Janine's home town";

      out.println(mars);
      out.println(this.mars);
   }
}

Listing 10-7: Calling the Code of Listing 10-6

  import static java.lang.System.out;

public class GetGoing {
  
   public static void main(String args[]) {
  
      out.println("main is running:");
    
      EnglishSpeakingWorld e =
                   new EnglishSpeakingWorld();
    
      //out.println(mars);  cannot resolve symbol
      out.println(e.mars);
      e.visitPennsylvania();
  }
}

Figure 10-7 shows a run of the code in Listings 2-10 and 6-4. Figure 10-8 shows a diagram of the code’s structure. In the GetGoing class, the main method creates an instance of the EnglishSpeakingWorld class. The variable e refers to the new instance. The new instance is an object with a variable named mars inside it. That mars variable has the value "red planet". The "red planet"mars variable is a field.

9781118407806-fg1007.tif

Figure 10-7: A run of the code in Listings 2-10 and 6-4.

technicalstuff.eps Another way to describe that mars field is to call it an instance variable, because that mars variable (the variable whose value is "red planet") belongs to an instance of the EnglishSpeakingWorld class. In contrast, you can refer to static fields (like the playerCount, totalOfAverages, and decFormat fields in Listing 10-4) as class variables. For example, playerCount in Listing 10-4 is a class variable because one copy of playerCount belongs to the entire PlayerPlus class.

Now look at the main method in Listing 10-7. Inside the GetGoing class’s main method, you aren’t permitted to write out.println(mars). In other words, a bare-faced reference to any mars variable is a definite no-no. The mars variable that I mention in the previous paragraph belongs to the EnglishSpeakingWorld object, not the GetGoing class.

9781118407806-fg1008.tif

Figure 10-8: The structure of the code in Listings 2-10 and 6-4.

However, inside the GetGoing class’s main method, you can certainly write e.mars because the e variable refers to your EnglishSpeakingWorld object. That’s nice.

Near the bottom of the code, the visitPennsylvania method is called. When you’re inside visitPennsylvania, you have another declaration of a mars variable, whose value is "Janine's home town". This particular mars variable is called a method-local variable because it belongs to just one method — the visitPennsylvania method.

So now you have two variables, both with the name mars. One mars variable, a field, has the value "red planet". The other mars variable, a method-local variable, has the value "Janine's home town". In the code, when you use the word mars, to which of the two variables are you referring?

The answer is, when you’re visiting Pennsylvania, the variable with value "Janine's home town" wins. When in Pennsylvania, think the way the Pennsylvanians think. When you’re executing code inside the visitPennsylvania method, resolve any variable name conflicts by going with method-local variables — variables declared right inside the visitPennsylvania method.

So what if you’re in Pennsylvania and need to refer to that two-mooned celestial object? More precisely, how does code inside the visitPennsylvania method refer to the field with value "red planet"? The answer is, use this.mars. The word this points to whatever object contains all this code (and not to any methods inside the code). That object, an instance of the EnglishSpeakingWorld class, has a big, fat mars field, and that field’s value is "red planet". So that’s how you can force code to see outside the method it’s in — you use the Java keyword this.

ontheweb_fmt.eps For more information on the keyword this, see Chapter 9.

Telling a variable where to go

Years ago, when I lived in Milwaukee, Wisconsin, I made frequent use of the local bank’s automatic teller machines. Machines of this kind were just beginning to become standardized. The local teller machine system was named TYME, which stood for Take Your Money Everywhere.

I remember traveling by car out to California. At one point, I got hungry and stopped for a meal, but I was out of cash. So I asked a gas station attendant, “Do you know where there’s a TYME machine around here?”

So you see, a name that works well in one place could work terribly, or not at all, in another place. In Listings 2-10 and 8-4, I illustrate this point (with more than just an anecdote about teller machines).

Listing 10-8: Tale of Atomic City

  import static java.lang.System.out;

class EnglishSpeakingWorld2 {
   String mars;

   void visitIdaho() {
      out.println("visitID is running:");

      mars = "  red planet";
      String atomicCity = "  Population: 25";

      out.println(mars);
      out.println(atomicCity);
   }

   void visitNewJersey() {
      out.println("visitNJ is running:");

      out.println(mars);
      //out.println(atomicCity);
      //  cannot resolve symbol
   }
}

Listing 10-9: Calling the Code of Listing 10-8

  public class GetGoing2 {

   public static void main(String args[]) {
     EnglishSpeakingWorld2 e =
                   new EnglishSpeakingWorld2();

     e.visitIdaho();
     e.visitNewJersey();
   }
}

Figure 10-9 shows a run of the code in Listings 2-10 and 8-4. Figure 10-10 shows a diagram of the code’s structure. The code for EnglishSpeakingWorld2 has two variables. The mars variable, which isn’t declared inside a method, is a field. The other variable, atomicCity, is a method-local variable and is declared inside the visitIdaho method.

9781118407806-fg1009.tif

Figure 10-9: A run of the code in Listings 2-10 and 8-4.

9781118407806-fg1010.tif

Figure 10-10: The structure of the code in Listings 2-10 and 8-4.

In Listing 10-8, notice where each variable can and can’t be used. When you try to use the atomicCity variable inside the visitNewJersey method, you get an error message. Literally, the message says cannot resolve symbol. Figuratively, the message says, “Hey, buddy, Atomic City is in Idaho, not New Jersey.” Technically, the message says that the method-local variable atomicCity is available only in the visitIdaho method because that’s where the variable was declared.

So back inside the visitIdaho method, you’re free to use the atomicCity variable as much as you want. After all, the atomicCity variable is declared inside the visitIdaho method.

And what about Mars? Have you forgotten about your old friend, that lovely 80-degrees-below-zero planet? Well, both the visitIdaho and visitNew​Jersey methods can access the mars variable. That’s because the mars variable is a field. That is, the mars variable is declared in the code for the EnglishSpeakingWorld2 class but not inside any particular method. (In my stories about the names for things, remember that people who live in both states, Idaho and New Jersey, have heard of the planet Mars.)

The lifecycle of the mars field has three separate steps:

  • When the EnglishSpeakingWorld2 class first flashes into existence, the computer sees String mars and creates space for the mars field.
  • When the visitIdaho method is executed, the method assigns the value "red planet" to the mars field. (The visitIdaho method also prints the value of the mars field.)
  • When the visitNewJersey method is executed, the method prints the mars value once again.

In this way, the mars field’s value is passed from one method to another.

Passing Parameters

A method can communicate with another part of your Java program in several ways. One of the ways is through the method’s parameter list. Using a parameter list, you pass on-the-fly information to a method as the method is being called.

So imagine that the information you pass to the method is stored in one of your program’s variables. What, if anything, does the method actually do with that variable? The following sections present a few interesting case studies.

Pass by value

According to my web research, the town of Smackover, Arkansas, has 2,232 people in it. But my research isn’t current. Just yesterday, Dora Kermongoos celebrated a joyous occasion over at Smackover General Hospital — the birth of her healthy, blue-eyed baby girl. (The girl weighs 7 pounds, 4 ounces, and is 21 inches tall.) Now the town’s population has risen to 2,233.

Listing 10-10 has a very bad program in it. The program is supposed to add 1 to a variable that stores Smackover’s population, but the program doesn’t work. Take a look at Listing 10-10 and see why.

Listing 10-10: This Program Doesn’t Work

  public class TrackPopulation {

   public static void main(String args[]) {
      int smackoverARpop = 2232;
    
      birth(smackoverARpop);
      System.out.println(smackoverARpop);
   }
    
   static void birth(int cityPop) {
      cityPop++;
   }
}

When you run the program in Listing 10-10, the program displays the number 2,232 onscreen. After nine months of planning and anticipation and Dora’s whopping seven hours in labor, the Kermongoos family’s baby girl wasn’t registered in the system. What a shame!

The improper use of parameter passing caused the problem. In Java, when you pass a parameter that has one of the eight primitive types to a method, that parameter is passed by value.

cross-reference.eps For a review of Java’s eight primitive types, see Chapter 4.

Here’s what this means in plain English: Any changes that the method makes to the value of its parameter don’t affect the values of variables back in the calling code. In Listing 10-10, the birth method can apply the ++ operator to cityPop all it wants — the application of ++ to the cityPop parameter has absolutely no effect on the value of the smackoverARpop variable back in the main method.

Technically, what’s happening is the copying of a value. (See Figure 10-11.) When the main method calls the birth method, the value stored in smackoverARpop is copied to another memory location — a location reserved for the cityPop parameter’s value. During the birth method’s ‑execution, 1 is added to the cityPop parameter. But the place where the original 2232 value was stored — the memory location for the smackoverARpop variable — remains unaffected.

9781118407806-fg1011.tif

Figure 10-11: Pass by value, under the hood.

remember.eps When you do parameter passing with any of the eight primitive types, the computer uses pass by value. The value stored in the calling code’s variable remains unchanged. This happens even if the calling code’s variable and the called method’s parameter happen to have the exact same name.

Returning a result

You must fix the problem that the code in Listing 10-10 poses. After all, a young baby Kermongoos can’t go through life untracked. To record this baby’s existence, you have to add 1 to the value of the smackoverARpop variable. You can do this in plenty of ways, and the way presented in Listing 10-11 isn’t the simplest. Even so, the way shown in Listing 10-11 illustrates a point: Returning a value from a method call can be an acceptable alternative to parameter passing. Look at Listing 10-11 to see what I mean.

After running the code in Listing 10-11, the number you see on your computer screen is the correct number, 2,233.

The code in Listing 10-11 has no new features in it (unless you call working correctly a new feature). The most important idea in Listing 10-11 is the return statement, which also appears in Chapter 7. Even so, Listing 10-11 presents a nice contrast to the approach in Listing 10-10, which had to be discarded.

Listing 10-11: This Program Works

  public class TrackPopulation2 {

   public static void main(String args[]) {
      int smackoverARpop = 2232;
    
      smackoverARpop = birth(smackoverARpop);
      System.out.println(smackoverARpop);
   }  
  
   static int birth(int cityPop) {
      return cityPop + 1;
   }
}

Pass by reference

In the previous section or two, I take great pains to emphasize a certain point — that when a parameter has one of the eight primitive types, the parameter is passed by value. If you read this, you probably missed the emphasis on the parameter’s having one of the eight primitive types. The emphasis is needed because passing objects (reference types) doesn’t quite work the same way.

When you pass an object to a method, the object is passed by reference. What this means to you is that statements in the called method can change any values that are stored in the object’s variables. Those changes do affect the values that are seen by whatever code called the method. Listings 2-10 and 12-4 illustrate the point.

Listing 10-12: What Is a City?

  class City {
   int population;
}

Listing 10-13: Passing an Object to a Method

  public class TrackPopulation3 {

   public static void main(String args[]) {
      City smackoverAR = new City();
      smackoverAR.population = 2232;
      birth(smackoverAR);
      System.out.println(smackoverAR.population);
   }
    
   static void birth(City aCity) {
      aCity.population++;
   }
}

When you run the code in Listings 2-10 and 12-4, the output that you get is the number 2,233. That’s good because the code has things like ++ and the word birth in it. The deal is, adding 1 to aCity.population inside the birth method actually changes the value of smackoverAR.population as it’s known in the main method.

To see how the birth method changes the value of smackoverAR.population, look at Figure 10-12. When you pass an object to a method, the computer doesn’t make a copy of the entire object. Instead, the computer makes a copy of a reference to that object. (Think of it the way it’s shown in Figure 10-12. The computer makes a copy of an arrow that points to the object.)

9781118407806-fg1012.tif

Figure 10-12: Pass by reference, under the hood.

In Figure 10-12, you see just one instance of the City class, with a population variable inside it. Now keep your eye on that object as you read the following steps:

  1. Just before the birth method is called, the smackoverAR variable refers to that object — the instance of the City class.
  2. When the birth method is called and smackoverAR is passed to the birth method’s aCity parameter, the computer copies the reference from smackoverAR to aCity. Now aCity refers to that same object — the instance of the City class.
  3. When the statement aCity.population++ is executed inside the birth method, the computer adds 1 to the object’s population field. Now the program’s one and only City instance has 2233 stored in its population field.
  4. The flow of execution goes back to the main method. The value of smackoverAR.population is printed. But smackoverAR refers to that one instance of the City class. So smackoverAR.population has the value 2233. The Kermongoos family is so proud.

Returning an object from a method

Believe it or not, the previous sections on parameter passing left one nook and cranny of Java methods unexplored. When you call a method, the method can return something right back to the calling code. In previous chapters and sections, I return primitive values, such as int values, or nothing (otherwise known as void). In this section, I return a whole object. It’s an object of type City from Listing 10-12. The code that makes this happen is in Listing 10-14.

Listing 10-14: Here, Have a City

  public class TrackPopulation4 {
  
   public static void main(String args[]) {
      City smackoverAR = new City();
      smackoverAR.population = 2232;
      smackoverAR = doBirth(smackoverAR);
      System.out.println(smackoverAR.population);
   }  
  
   static City doBirth(City aCity) {
      City myCity = new City();
      myCity.population = aCity.population + 1;
      return myCity;
   }  
}

If you run the code in Listing 10-14, you get the number 2,233. That’s good. The code works by telling the doBirth method to create another City instance. In the new instance, the value of population is 2333. (See Figure 10-13.)

9781118407806-fg1013.tif

Figure 10-13: The doBirth method creates a City instance.

After the doBirth method is executed, that City instance is returned to the main method. Then, back in the main method, that instance (the one that doBirth returns) is assigned to the smackoverAR variable. (See Figure 10-14.) Now smackoverAR refers to a brand-new City instance — an instance whose population is 2,233.

9781118407806-fg1014.tif

Figure 10-14: The new City instance is assigned to the smack​overAR variable.

In Listing 10-14, notice the type consistency in the calling and returning of the doBirth method:

  • The smackoverAR variable has type City. The smackoverAR variable is passed to the aCity parameter, which is also of type City.
  • The myCity variable is of type City. The myCity variable is sent back in the doBirth method’s return statement. That’s consistent, because the doBirth method’s header begins with static City doBirth(blah, blah, blah... — a promise to return an object of type City.
  • The doBirth method returns an object of type City. Back in the main method, the object that the call to doBirth returns is assigned to the smackoverAR variable, and (you guessed it) the smackoverAR variable is of type City.

Aside from being very harmonious, all this type agreement is absolutely necessary. If you write a program in which your types don’t agree with one another, the compiler spits out an unsympathetic incompatible types message.

Epilogue

Dora Kermongoos and her newborn baby daughter are safe, healthy, and resting happily in their Smackover, Arkansas, home.

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

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