Skip to content

Latest commit

 

History

History
140 lines (103 loc) · 4.58 KB

constructors.md

File metadata and controls

140 lines (103 loc) · 4.58 KB

Constructors

Overview

Suppose you define:

class Point {
    double x;
    double y;
}

Every time you create an instance of Point, you have to initialize the instance variables:

Point p = new Point();
p.x = 3;
p.y = 5;

It would be more convenient if you could specify these values on the line where you created the object:

Point p = new Point(3, 5);

You can, in fact, do this if the definition of Point includes an appropriate constructor:

class Point {
    
    double x;
    
    double y;
    
    Point(double initialX, double initialY) {
        x = initialX;
        y = initialY;
    }

}

The constructor looks much like a static method, but:

  • It is not declared static,
  • It has no return type, and
  • It has exactly the same name as the class (starting with an upper-case letter).

Every time you use new to create an object, you are calling a constructor.

The Default Constructor

If you do not explicitly define a constructor (as in the first definition of Point above), Java automatically provides a default constructor that takes no arguments and doesn't do anything. This is what was used in the first object creation above.

If you do explicitly define a constructor, you do not get a default constructor. When we add a constructor with parameters to the definition of Point, it is no longer legal to say new Point().

this

The parameter names initialX and initialY above are a bit awkward. It would be nice if you could define the constructor as:

Point(double x, double y) {
    x = x;
    y = y;
}

Lines like

x = x;

seem suspicious. In fact, this constructor does not work properly. The parameters are new local variables, not references to the instance variables. Inside the method x refers to the parameter, not the instance variable. The parameter is said to shadow the instance variable, because it prevents the light of the instance variable from reaching down into the depths of the method. The line

x = x;

simply sets the parameter to its own value, which of course has no effect.

All is not lost. The instance variable can still be referred to as this.x, that is, the x instance variable of this, which is the object currently being created. You can therefore use the parameter names you want:

Point(double x, double y) {
    this.x = x;
    this.y = y;
}

Resources

  • Sedgewick and Wayne, Introduction to Programming in Java, Section 3.2
  • Horstmann, Core Java, Volume I: Fundamentals, 11th Edition, Sections 4.3.4 and 4.6

Questions

  1. ⭐ Where should an instance variable be initialized?
  2. ⭐ Describe a situation where it's necessary to use this.
  3. ⭐⭐ Can constructors be overloaded?
  4. ⭐⭐ Explain why the program below does not print 5.
    public class Box {
    
      private int x;
    
      public Box() {
          int x = 5;
      }
    
      public static void main(String[] args) {
          System.out.println(new Box().x);
      }
    
    }
  5. ⭐⭐⭐ Can a constructor call another constructor in the same class?

Answers

  1. In a constructor. It is legal to initialize them where they are declared, but it's better style to do it in a constructor. If you initialize one both where it is declared and in a constructor, anyone reading your code will have to both notice this and look up which one takes precedence. It is better to be consistent. Since complicated multi-line initializations (e.g., arrays that have to be filled in with loops) can only happen in the constructor, it's best to put all initializations there.
  2. When a local variable (say, x) shadows an instance variable, the instance variable must be referred to as this.x.
  3. Yes. For example, the built-in String class has one constructor that takes a char[] and one that takes another String (and creates a copy of it).
  4. The constructor does not initialize x; it creates a new local variable with the same name.
  5. Yes. Doing so is referred to as constructor chaining and can be useful to avoid code duplication. The only way to effect chaining is through the use of the this keyword as in the following example.
    public class Complex {
    
      private double re, im;
    
      // Initial value fully specified.
      public Complex(double real, double imag) {
        re = real;
        im = imag;
      }
    
      // No initial value provided; initialize value to zero
      // relying on the other constructor.
      public Complex() {
        this(0.0, 0.0);
      }
    
    }