|
| |
As we said earlier, we can
create an instance (object) by using:
new Circle();
which uses:
- the new operator to
allocate space for the
instance
- a constructor to initialize
the instance
What is a constructor?
- It is a special method
- Its name is the same as the class name
(case-sensitive)
- It may have zero or more arguments (just
like regular methods)
- It has no explicit return type
- It must not use a return type of void
- It may appear that the constructor returns an instance of its class, but
in fact, it's the new
operator that does that.
- It must not use a return statement to return a value
- Strangely, a constructor is not a member of its class
Implicit and Explicit Constructors
Remember that, in our class
Circle, we had:
import java.lang.Math;
public class Circle
{
// Accessor methods
public double getX() { return m_x; }
public double getY() { return m_y; }
public double getRadius() { return m_r; }
// Mutator methods
public void setX(double v) { m_x = v; }
public void setY(double v) { m_y = v; }
public void setRadius(double r) { m_r = r; }
// Operations/Attributes
public double getCircumference()
{ return 2 * Math.PI * m_r; }
public double getArea()
{ return Math.PI * m_r*m_r; }
double m_x, m_y; // coordinates of center
double m_r; // radius
}
|
So
where are the constructors in this Circle class?
Answer: There are no
explicit constructors, only implicit ones.
The Default Constructor
If a class has no explicitly specified
constructors, then a default constructor is
automatically generated for that class by the Java compiler
- A default constructor is a
constructor that takes zero arguments
- It is sometimes called a no-argument
(or no-arg) constructor)
- In the case of the above Circle class,
the default constructor does nothing obvious (note
that the class fields will be automatically
initialized to zero values).
- If you wish to write some explicitly
specified constructors and a no-argument
constructor for a class, you must write the
no-argument constructor yourself.
Multiple Constructors
Sometimes, you need to
initialize class instances in different ways. So:
- A class may have more than one
constructor
- Because each constructor must have the exact same name as the class
name, each separate constructor is therefore an overloaded
method with a different signature
(overloaded just like regular methods)
For example:
public class Circle
{
// Constructors
public Circle(double x, double y, double r)
{ m_x = x; m_y = y; m_r = r; }
public Circle(double r)
{ m_x = 0.0; m_y = 0.0; m_r = r; }
public Circle(Circle c)
{ m_x = c.m_x; m_y = c.m_y; m_r = c.m_r; }
public Circle()
{ m_x = m_y = m_r = 0.0; }
// Accessor methods
public double getX() { return m_x; }
public double getY() { return m_y; }
public double getRadius() { return m_r; }
// Mutator methods
public void setX(double v) { m_x = v; }
public void setY(double v) { m_y = v; }
public void setRadius(double r) { m_r = r; }
// Operations/Attributes
public double getCircumference()
{ return 2 * Math.PI * m_r; }
public double getArea()
{ return Math.PI * m_r*m_r; }
double m_x, m_y; // coordinates of center
double m_r; // radius
}
|
this()
But there's a better way to
write this, to avoid code repetition:
The first statement of a
constructor may be an explicit call to another
constructor of the same class, using the syntax:
this( /* arguments */ );
For example:
public class Circle
{
// Constructors
public Circle(double x, double y, double r)
{ m_x = x; m_y = y; m_r = r; }
public Circle(double r)
{ this(0.0, 0.0, r); }
public Circle()
{ this(0.0, 0.0, 0.0); }
// Accessor methods
public double getX() { return m_x; }
public double getY() { return m_y; }
public double getRadius() { return m_r; }
// Mutator methods
public void setX(double v) { m_x = v; }
public void setY(double v) { m_y = v; }
public void setRadius(double r) { m_r = r; }
// Operations/Attributes
public double getCircumference()
{ return 2 * Math.PI * m_r; }
public double getArea()
{ return Math.PI * m_r*m_r; }
double m_x, m_y; // coordinates of center
double m_r; // radius
}
|
In this way, you can write a constructor
whose code is shared among other constructors -- no need to
cut and paste code!
"Copy Constructors"
In C++, there is another kind of
constructor that is commonly defined -- a copy
constructor, which is usually of the form:
Circle(const Circle &c) // This is valid C++, but invalid Java
In C++, a copy constructor is automatically
generated for you
for each class that does not include an explicitly written copy constructor.
(C++ also automatically generates an assignment operator for each class
that does not include an explicitly written assignment operator.)
- The generated copy constructor does a member-wise (shallow) copy.
- In some cases, this is incorrect behavior, and will
get you into serious trouble.
- In other cases, you don't want a copy
constructor at all, because it doesn't make sense for your
particular class.
- C++ copy constructors can cause a lot
of trouble.
- If you don't want C++ to generate a
copy constructor for you, or if you want to write
your own copy constructor, you have to explicitly write your own
copy constructor.
In Java, you can also create a copy
constructor:
Circle(Circle c)
but Java will not automatically
generate one for you.
If you want a copy constructor for a Java
class, you must write one yourself.
For example:
public class Circle
{
// Constructors
public Circle(double x, double y, double r)
{ m_x = x; m_y = y; m_r = r; }
public Circle(double r)
{ this(0.0, 0.0, r); }
public Circle()
{ this(0.0, 0.0, 0.0); }
public Circle(Circle c)
{ this(c.m_x, c.m_y, c.m_r); }
// Accessor methods
public double getX() { return m_x; }
public double getY() { return m_y; }
public double getRadius() { return m_r; }
// Mutator methods
public void setX(double v) { m_x = v; }
public void setY(double v) { m_y = v; }
public void setRadius(double r) { m_r = r; }
// Operations/Attributes
public double getCircumference()
{ return 2 * Math.PI * m_r; }
public double getArea()
{ return Math.PI * m_r*m_r; }
double m_x, m_y; // coordinates of center
double m_r; // radius
}
|
This is not normally done.
Note: The proper
way to do this in Java is to use clone()
-- more on cloning, later.
|