Construction and Constructors


When you invoke new to construct a new instance of a class, automatically a call is made to a piece of code in that class, called its constructor. This may come as a surprise, because for the past two chapters you have constructed objects without ever writing constructors, or even knowing about them. In a moment you will see how this works out.

A constructor looks like a method. In fact, there are only two differences between a constructor and a method:

  • A constructor has no return type.

  • The constructor's name is the same as the class's name.

Like a method, a constructor has a body, enclosed in curly brackets. The code in the body can initialize the newborn object. In fact, this initialization is the basic job of constructors. A constructor can always assume that the object's variables and methods (whether declared in the class or inherited) exist and are accessible for reading, writing, and calling.

Let's add a constructor to the Worker class. Assume that all workers in the company have the same salary: $34,567.89. The Worker class (with a different main() method) becomes the following:

 1. public class Worker extends Employee 2. {  3.   boolean  getsOvertime;  4.  5.   Worker()  6.   {  7.     salary = 34567.89f;  8.   }  9. 10.   void dumpSalary () 11.   { 12.     System.out.println("Salary = " + salary); 13.   } 14. 15.   public static void main(String[] args) 16.   { 17.     Worker dagwood = new Worker(); 18.     dagwood.dumpSalary(); 19.   } 20. }

The constructor is lines 5-8. Constructors, variables, and methods can appear in any order in the body of a class definition. However, it is common practice to have variables come first, followed by constructors, followed by methods. Usually, the main() method comes at the end. When this application is run, line 17 constructs a new instance of Worker. First, space for all variables is allocated. Then the constructor code is called. Line 7 of the constructor initializes salary to 34567.89, so the call to printSalarydumpSalary() prints out Salary = 34567.89.

Overloading Constructors

It is not especially realistic to expect every worker in a company to have the same salary. Fortunately, you can pass arguments into a constructor the same way you pass them into a method. As with a method, you can put an argument list inside the parentheses that follow the constructor name. Those arguments are accessible within the method. The next version of Worker has a constructor that accepts an argument.

 1. public class Worker extends Employee  2. {  3.   boolean  getsOvertime;  4.  5.   Worker(float sal)  6.   {  7.     salary = sal;  8.   }  9. 10.   void dumpSalary () 11.   { 12.     System.out.println("Salary = " + salary); 13.   } 14. 15.   public static void main(String[] args) 16.   { 17.     Worker dagwood = new Worker(55555.55f); 18.     dagwood.dumpSalary(); 19.   } 20. }

The constructor now takes a float argument, and the invocation on line 17 passes a float. The output is Salary = 34567.89.

In Chapter 4, "Methods," you learned that methods are polymorphic. That is, different methods within a class may share a common name, as long as their argument lists are different. The practice of reusing a method name in a class is called overloading. (The term has a negative connotation in real life. When people or bridges are overloaded, that's bad. But in programming, there is nothing bad about overloading.) You can also overload a class's constructor so that the class has multiple constructors, as shown here:

public class Manager extends Employee {   Worker[] workers;   Manager(int nWorkers)   {     workers = new Worker[nWorkers];   }   Manager(float sal, int nWorkers)   {     salary = sal;     workers = new Worker[nWorkers];   } }

This class has two constructors. In both versions, you specify the number of workers. In the second version, you also specify the manager's salary.

Default Constructors

This section answers an important question: In the previous chapter and the first part of this one, how was it possible to construct objects in classes that didn't have any constructors? To understand the answer, you have to know what a no-args constructor is. It's just a constructor with an empty argument list.

When you create a class with no constructors, the compiler creates a no-args constructor automatically. A no-args constructor that is created automatically is called a default constructor. You only get a default constructor if your class does not explicitly have any constructors. If your class has constructors, no matter how many, no-args or otherwise, no default constructor is created for you.

This mechanism assures that every class has at least one constructor, even if the class was written by someone who has never heard of constructors!

A default constructor does almost nothing. It contains no initialization code, because it contains no code at all. All it does is participate in the constructor chain mechanism, which is discussed in the next section.

The Chain of Constructions

Objects are like onions. They consist of layers within layers within layers. Consider the Submarine class from InheritLab's Transport scenario. This class extends WaterTransport, which extends Transport, which extends Object. One way to visualize an instance of Submarine is as an instance of Object forming an inner core. Around this core is a layer consisting of the data and methods of an instance of Transport. In turn, this layer is surrounded by a WaterTransport layer, which is surrounded by a Submarine layer. The layered structure is shown in Figure 8.4.

click to expand
Figure 8.4: Object layers

When a Submarine instance is constructed, each layer's constructor is called in turn, starting with Object (the innermost layer) and moving outward. This mechanism doesn't have an official name, but we'll call it the chain of constructors.

The ConstructorLab animated illustration shows the chain of constructors in action. Start the program by typing java inherit.ConstructorLab. At first glance, the program looks just like the InheritLab program that you already saw earlier in this chapter. But when you click on an object, the pop-up menu has an extra Construct... item. If you make this selection, you see an animation of the layer-by-layer construction of the class you've selected. Try it with the Submarine class from the Transport scenario.

Here's how the chain-of-constructors mechanism works: When a constructor is called, but before any of its code is executed, a call is made to the no-args constructor of the superclass. If the superclass is not Object, before any of its own constructor code is executed, a call is made to its own superclass's no-args constructor. This chain of calls continues up the inheritance hierarchy until it reaches Object, which has no superclass.

So when you call a constructor for Submarine, the first thing that happens is a call to the no-args constructor for WaterTransport. Within that constructor, the first thing that happens is a call to the no-args constructor for Transport. Finally, within Transport's no-args constructor, a call is made to the Object no-args constructor. At this point, the chain ends.

Why does Java do this? Consider the benefits if you are the person who writes the Submarine class code. Your constructors might need to access the data of the WaterTransport superclass, which might be initialized by WaterTransport's constructor. That constructor might need to access the data of its own superclass, and so on. The chain-of-constructors mechanism guarantees that by the time a class's constructor code begins to execute, the superclass portion of the class is intact and valid.

Note

Bear in mind that the mechanism operates without your having to do anything at all. You don't have to make it happen. As a matter of fact, you can't avoid it. But you can slightly alter its behavior.

As you know, constructor invocation begins with an automatic call to the superclass's no-args constructor. Recall that constructors can be overloaded so that alternate superclass constructors could be available. There are two reasons why you might want to invoke a different superclass constructor:

There is no superclass no-args constructor. This happens if you explicitly give the superclass one or more constructors that take arguments. Now you don't get an automatic default constructor, so unless you explicitly coded a no-args constructor for the superclass, there won't be one.

The superclass has a no-args constructor that doesn't do what you want. But there's another constructor that does exactly what you want.

In either of these situations, you still want the construction chain to happen. You just want to invoke a different version of the superclass constructor. This is done with the super keyword.

To see how super works, let's extend the Manager class from earlier in this chapter. The class looks like this:

public class Manager extends Employee {   Worker[] workers;   Manager(int nWorkers)   {     workers = new Worker[nWorkers];   }   Manager(float sal, int nWorkers)   {     salary = sal;     workers = new Worker[nWorkers];   } }

This class provides its own constructors, so there is no default constructor provided by the compiler. Neither is there an explicitly coded no-args constructor, so any subclass of Manager will have to modify the construction chain to avoid invocation of a constructor that doesn't exist.

Let's create a subclass called Officer. An officer is a high-ranking manager who may or may not serve on the board of directors. The subclass will have an int variable called nYrsOnBoard, which tells how many years (if any) this officer has served on the board. There will also be a single constructor whose arguments are the number of workers reporting to this officer and the initial value for nYrsOnBoard. Officer salaries are $850,000.00. Nice work if you can get it. The Officer code looks like this:

 1. public class Officer extends Manager  2. {  3.   int nYrsOnBoard;  4.  5.   Officer(int nWorkers, int initialNYrs)  6.   {  7.     super(850000f, nWorkers);  8.     nYrsOnBoard = initialNYrs;  9.   } 10. } 

The line to notice is line 7, which introduces the super keyword. It looks like a call to a method called super(). In fact, the code in the parentheses is an argument list, but you aren't allowed to create a method with that name. Instead, super is a signal that you are modifying the construction chain by requesting a call to a different superclass constructor (that is, one that isn't the no-args version). This use of super may only appear as the first executable code in a constructor (so if you reversed lines 7 and 8, you would get a compiler error).

Line 7 invokes an alternative superclass constructor, but which one? This is determined by the argument list inside the parentheses that follow super. Here there are two values: a float followed by an int. So the Manager constructor that gets invoked will be the version that takes two arguments: a float and int. If you look at the Manager constructor, you'll see that this corresponds to the second of its constructors.




Ground-Up Java
Ground-Up Java
ISBN: 0782141900
EAN: 2147483647
Year: 2005
Pages: 157
Authors: Philip Heller

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net