Working with Overloaded Constructors
A constructor can refer to another constructor in the same class or the immediate superclass using special forms of the this and super references. We’ll discuss the first case here and return to that of the superclass constructor after we have talked more about subclassing and inheritance. A constructor can invoke another overloaded constructor in its class using the self-referential method call this()with appropriate arguments to select the desired constructor. If a constructor calls another constructor, it must do so as its first statement:
- class Car {
- String model;
- int doors;
- Car( String model, int doors ) {
- this.model = model;
- this.doors = doors;
- // other, complicated setup
- ...
- }
- Car( String model ) {
- this( model, 4 /* doors */ );
- }
- ...
- }
复制代码
In this example, the class Car has two constructors. The first, more explicit, one accepts arguments specifying the car’s model and its number of doors. The second constructor takes just the model as an argument and, in turn, calls the first constructor with a default value of four doors. The advantage of this approach is that you can have a single constructor do all the complicated setup work; other auxiliary constructors simply feed the appropriate arguments to that constructor.
The special call to this() must appear as the first statement in our delegating constructor. The syntax is restricted in this way because there’s a need to identify a clear chain of command in the calling of constructors. At the end of the chain, Java invokes the constructor of the superclass (if we don’t do it explicitly) to ensure that inherited members are initialized properly before we proceed.
There’s also a point in the chain, just after invoking the constructor of the superclass, where the initializers of the current class’s instance variables are evaluated. Before that point, we can’t even reference the instance variables of our class. We’ll explain this situation again in complete detail after we have talked about inheritance.
For now, all you need to know is that you can invoke a second constructor (delegate to it) only as the first statement of your constructor. For example, the following code is illegal and causes a compile-time error:
- Car( String m ) {
- int doors = determineDoors();
- this( m, doors ); // Error: constructor call
- // must be first statement
- }
复制代码
The simple model name constructor can’t do any additional setup before calling the more explicit constructor. It can’t even refer to an instance member for a constant value:
- class Car {
- ...
- final int default_doors = 4;
- ...
- Car( String m ) {
- this( m, default_doors ); // Error: referencing
- // uninitialized variable
- }
- ...
- }
复制代码
The instance variable defaultDoors is not initialized until a later point in the chain of constructor calls setting up the object, so the compiler doesn’t let us access it yet. Fortunately, we can solve this particular problem by using a static variable instead of an instance variable:
- class Car {
- ...
- static final int DEFAULT_DOORS = 4;
- ...
- Car( String m ) {
- this( m, DEFAULT_DOORS ); // Okay!
- }
- ...
- }
复制代码
The static members of a class are initialized when the class is first loaded into the virtual machine, so it’s safe to access them in a constructor.