6.3 Constructors
In creating objects of the type Fraction, we have been using statements
that have a form like the following.
Fraction f = new Fraction();
The parentheses in the expression Fraction() make it look like a method
call and, in fact, it is. The method is called a constructor method. We did
not create such a method but, for every class, Java automatically creates
a default constructor method that has the same identifier as the class.
Constructor methods are instance methods used to initialize objects
at the "tIme the objects are created.-The default method initializes any
numeric fields to zero, boolean fields to false, and reference fields to the
value null. We can, however, write our own constructors that do whatever
initialization we wish. As an example, we can use a constructor to initialize
objects of type Fraction as follows:
Example 1
Suppose, in the class Fraction, we created the following constructor:
public Fraction (int n, int d)
{
num = n;
den = d;
}
|
|
Then, in our main method, say, we could write
Fraction f = new Fraction(2,3);
This would declare f to be of type Fraction, create an object of type
Fraction, set f to refer to that object, and initialize the object to represent
the fraction 2/3.
There are a number of things about constructors that the example
displays.
- The identifier of the constructor method is exactly the same as the
identifier of the class; both are called Fraction.
- Unlike every method that we have seen so far, the constructor method
does not specify a return type (not even VOid). It is implicit that the
method returns an object of type Fraction.
- The constructor is an instance method. Thus, it can refer to the
instance fields of the class (num and den), just as any other instance
method can.
- The call to the constructor method differs from other calls to instance
methods in that it does not use the dot notation. We wrote
f = new Fraction(2,3); rather than new f.Fraction(2,3);
- The parameters to the constructor method were called n and d so
that their identifiers did not conflict with num and den, the identifiers
of the object that is implicitly associated with the method. If we had
wanted to use num and den as identifiers of the explicit parameters,
we could have written the definition as follows:
public Fraction (int num, int den)
{
this.num num;
this.den den;
}
|
|
As usual, this means the current implicit object. The identifiers on
the left side of the assignment statements refer to the this object's
num and den fields while the identifiers on the right side refer to the
explicit parameters to the method.
Java does not restrict us to having only one constructor method for a
class. Like any other methods, constructors can be overloaded with each
version having its own signature and each doing some different kind of
initialization.
Example 2
The following constructor for the Fraction class could be used to create a
Fraction object that has the same values as an existing Fraction object.
public Fraction (Fraction f)
{
num f .num;
den f.den;
}
|
|
We can even replace the default constructor with one that does the
kind of initialization that we want. For our Fraction class, the default
constructor will, given the call
Fraction f = new Fraction();
assign both the num and den fields the value zero, so that the resulting
object represents the indeterminate fraction 0/0. If we wanted to, we could
replace this by a constructor that creates a fraction that represents 1/0.
Example 3
A constructor that initializes Fraction objects to represent 0/1 would take
the following form:
public Fraction()
{
num = 0;
den = 1;
}
|
|
This constructor could be invoked by the call
Fraction f = new Fraction();
just as the default constructor is called.
To show how these methods could be used, consider the following fragment:
Fraction p = new Fraction(3,5);
Fraction q = new Fraction(p);
Fraction r = new Fraction();
|
|
The first statement uses our first constructor to create an object representing
the fraction 3/5. The second statement creates another object that
also represents the fraction 3/5. The third statement creates an object that
represents the fraction 0/1. The diagram illustrates the results.
We said, at the start of this section, that Java supplies a default constructor
if we do not write our own. However, if we do create our own
constructor(s), the default no longer operates. In such a situation, if we
want to have a constructor that has no parameters and does only basic
initialization, we must write it ourselves.
Example 4
The constructor
public Fraction ()
{
num = den = 0;
}
|
|
performs the actions of the default constructor for the Fraction class.
If a class has multiple constructors, it is sometimes possible to use the
code from one constructor in another. The next example illustrates this
idea.
Example 5
Suppose that a Student class has fields for a name, student number, and
number of credits. Normally, a new student will not have any credits. The
constructor for such a student might take the form
public Student (String n, String sn)
{
name = n;
studentNumber = sn;
credits = 0;
}
|
|
Sometimes a new student will already have some credits from another
school. To handle such cases, we could write another constructor.
public Student (String n, String sn, int c)
{
name = n;
studentNumber = sn;
credits = c;
}
|
|
Notice that the two constructors have two lines of code that are identical.
It is usually a good idea to avoid such repetition of multiple lines of code
because, if a mistake is found or if the program is being modified at a later
time, then the code must be changed in more than one place. We can avoid
such repetition here by rewriting the first constructor as follows.
public Student (String n, String sn)
{
this(n,sn,O);
}
|
|
In Example 5, we have used this in a new way, as a reference to the constructor
of the current implicit object. If a constructor contains a call to
another constructor, that call must be the first statement of the constructor.
Exercise 6.3
- Extend the definition of the Fraction class that we have been
developing to include the constructors discussed in this section.
- Write a main method that first constructs two Fraction objects
representing the fractions 5/7 and 3/8 and then creates two other
Fraction objects whose values are the sum and product of the
original fractions. The method should produce no output; we
will deal with printing of objects shortly. Use the methods plus
and times from Section 6.2 in your method.
For the class Circle defined as follows
class Circle
{
double x; // x-coordinate of centre
double y; // y-coordinate of centre
double r; // radius
}
- Write a constructor method that has no parameters. The method
should construct a Circle object with centre (0,0) and radius
l.
- Write a constructor method that has three parameters representing
the coordinates of the centre and the radius of the object to
be constructed.
- Write a constructor method with a parameter, an object of type
Circle. The method should construct a new Circle object with
the same field values as those of the parameter.
| |