Previous Table of Contents Next


14.3.2.3. Method Overloading

The surprising thing in this example (not so surprising if you’re a C++ programmer) is that all the constructor methods have the same name! So how can the compiler tell them apart? The way that you and I tell them apart is that the four methods take different arguments and are useful in different circumstances. The compiler tells them apart in the same way. In Java, a method is distinguished by its name, and by the number, type, and position of its arguments. This is not limited to constructor methods—any two methods are not the same unless they have the same name, and the same number of arguments of the same type passed at the same position in the argument list. When you call a method and there is more than one method with the same name, the compiler automatically picks the one that matches the data types of the arguments you are passing.

Defining methods with the same name and different argument types is called method overloading. It can be a convenient technique, as long as you only give methods the same name when they perform similar functions on slightly different forms of input data. Overloaded methods may have different return types, but only if they have different arguments. Don’t confuse method overloading with method overriding, which we’ll discuss later.

14.3.2.4. this Again

There is a specialized use of the this keyword that arises when a class has multiple constructors—it can be used from a constructor to invoke one of the other constructors of the same class. So we could rewrite the additional constructors from Example 14.9 in terms of the first one like this:

   public Circle(double x, double y, double r) {
       this.x = x; this.y = y; this.r = r;
}
   public Circle(double r) { this(0.0, 0.0, r); }
   public Circle(Circle c) { this(c.x, c.y, c.r); }
   public Circle() { this(0.0, 0.0, 1.0); }

Here, the this() call refers to whatever constructor of the class takes the specified type of arguments. This would be a more impressive example, of course, if the first constructor that we were invoking did a more significant amount of initialization, as it might, for example, if we were writing a more complicated class.

There is a very important restriction on this this syntax: It may only appear as the first statement in a constructor. It may, of course, be followed by any additional initialization that a particular version of the constructor needs to do. The reason for this restriction involves the automatic invocation of superclass constructor methods, which we’ll explore later in this section.

14.3.3. Class Variables

In our Circle class definition, we declared three “instance” variables: x, y, and r. Each instance of the class—each circle—has its own copy of these three variables. These variables are like the fields of a struct in C—each instance of the struct has a copy of the fields. Sometimes, though, we want a variable of which there is only one copy—something like a global variable in C.

The problem is that Java doesn’t allow global variables. (Actually, those in the know consider this a feature!) Every variable in Java must be declared inside a class. So Java uses the static keyword to indicate that a particular variable is a class variable rather than an instance variable. That is, that there is only one copy of the variable, associated with the class, rather than many copies of the variable associated with each instance of the class. The one copy of the variable exists regardless of the number of instances of the class that are created—it exists and can be used even if the class is never actually instantiated.

This kind of variable, declared with the static keyword, is often called a static variable. I prefer (and recommend) the name “class variable” because it is easily distinguished from its opposite, “instance variable.” We’ll use both terms in this chapter.

14.3.3.1. An Example

As an example (a somewhat contrived one), suppose that while developing the Circle class we wanted to do some testing on it and determine how much it gets used. One way to do this, would be to count the number of Circle objects that are instantiated. To do this, we obviously need a variable associated with the class, rather than with any particular instance. Example 14.10 shows how we can do it—we declare a static variable and increment it each time we create a Circle.

EXAMPLE 14.10. Static variable example.

   public class Circle {
       static int num_circles = 0;
       // class variable: how many circles created
       public double x, y, r;
       // instance vars: the center and the radius

       public Circle(double x, double y, double r) {
           this.x = x; this.y = y; this.r = r;
           num_circles++;
       }
       public Circle(double r) { this(0.0, 0.0, r); }
       public Circle(Circle c) { this(c.x, c.y, c.r); }
       public Circle() { this(0.0, 0.0, 1.0); }

       public double circumference() { return 2 * 3.14159 * r; }
       public double area() { return 3.14159 * r*r; }
   }

14.3.3.2. Accessing Class Variables

Now that we are keeping track of the number of Circle objects created, how can we access this information? Because static variables are associated with the class rather than with an instance, we access them through the class rather than through the instance. Thus, we might write:17


17Recall that System.out.println() prints a line of text, and that the string concatenation operator, +, converts nonstring types to strings as necessary.
   System.out.println(“Number of circles
       created: “ + Circle.num_circles);

Notice that in our definition of the constructor method in Example 14.10 we just used num_circles instead of Circle.num_circles. We’re allowed to do this within the class definition of Circle itself. Anywhere else, though, we must use the class name as well.


Previous Table of Contents Next