Constructors

Figure 228. Creating and initializing rectangles Slide presentation
int a;
a = 33;
Rectangle r = new Rectangle();

r.width = 28;
r.height = 10;
r.hasSolidBorder = false;

Combining statements desired:

int a = 33; // works!
Rectangle r = new Rectangle(28, 10, false);//how ???

Figure 229. Defining a constructor Slide presentation
public class Rectangle {
    int width, height;
    boolean hasSolidBorder;
         ...
    public  Rectangle  (int width, int height, boolean hasSolidBorder){
        this.width = width;
        this.height = height;
        this.hasSolidBorder = hasSolidBorder;
    }
}

Similar to Figure 204, “Method definition syntax ” but:

No return type declaration.

Constructor's name equals class name.

Figure 230. Constructor syntax Slide presentation
[access modifier] constructorName (listOfArguments) {
    [constructor body]
}
Empty argument list

Default constructor e.g. obj = new MyClass().

Non-empty argument list

Non-default constructor e.g. :

obj = new String("xyz");

Figure 231. Constructors Slide presentation
  • Can only be executed on object creation.

  • Are being called prior to any non-constructor method.

  • Only one of potentially multiple constructors will be executed exactly one time.

    However nesting is possible.


Figure 232. Multiple overloaded constructors Slide presentation
public class Rectangle {
    int width, height;

    public Rectangle() {
        width = height = 1;
    }
    public Rectangle(int width, int height){
        this.width = width;
        this.height = height;
    }
    public Rectangle(int widthAndHeight) {
        width = height = widthAndHeight;
    }
}
Multiple overloaded constructors

Figure 233. Constructor calls within constructor Slide presentation
public class Rectangle {
  int width, height;

  public Rectangle(int width,
                int height){
    this.width = width;
    this.height = height;
  }
  public Rectangle() {
    width = height = 1;
  }
  public Rectangle(
     int widthAndHeight) {
    width = height =
          widthAndHeight;
  }
}
   public class Rectangle {
     int width, height;

 ┏━▶ public Rectangle(int width,
                     int height){
      this.width = width;
      this.height = height;
    } 
    public Rectangle() { 
 ┣━◀━━ this(1, 1);           
    }
    public Rectangle(
      int widthAndHeight) {
 ┗━◀━━ this(widthAndHeight,   
            widthAndHeight); 
     }
   }

Reusing constructor Rectangle(int width, int height) with parameters width = height = 1.

Reusing constructor Rectangle(int width, int height) with parameters width = height = widthAndHeight.


Figure 234. Instances by overloaded constructors Slide presentation
Rectangle standard = new Rectangle(); // 1 x 1
Rectangle square = new Rectangle(2); // 2 x 2
Rectangle individual = new Rectangle(2, 7); // 2 x 7
Instances by overloaded constructors

Figure 235. No constructor vs. default constructor Slide presentation
Equivalent: Rectangle r = new Rectangle();
public class Rectangle {
    int width, height;
    boolean hasSolidBorder;

    // Default constructor, empty body.
    public Rectangle ( ){}
}
public class Rectangle {
    int width, height;
    boolean hasSolidBorder;

  // No constructor at all
}

Figure 236. Non - default constructor, but no default constructor Slide presentation
public class Rectangle {
  int width, height;
  boolean hasSolidBorder;

  // Non-default constructor
  public Rectangle(int width,
                  int height,
    boolean hasSolidBorder){
      this.width = width;
      this.height = height;
      this.hasSolidBorder =
                hasSolidBorder;
  }

 // No defined default constructor.
}
// o.K.: Using non-default
// constructor.

Rectangle r = 
   new Rectangle(3, 6, false);
// Wrong: Default constructor
// undefined, but non-default
// constructor present.

Rectangle r = new Rectangle();

exercise No. 96

Modeling geometry objects: Rectangles

Q:

We want to represent rectangles being defined by width and height to allow for the subsequently demonstrated operations:

final Rectangle r = new Rectangle(8, 5); 

System.out.println("Perimeter:" + r.getPerimeter());
System.out.println("Area:" + r.getArea());

r.setWidth(4); 
r.setHeight(7);

System.out.println("Perimeter:" + r.getPerimeter()); 
System.out.println("Area:" + r.getArea());

Creating an instance of class Rectangle by calling a non-default constructor which allows for providing width (8) and height (5).

Returning the rectangle's perimeter,

Returning the rectangle's area.

Setting with and height to new values.

Write (possibly) changed perimeter and area values.

You may start from the following Rectangle class dummy implementation:

/**
 * Representing rectangular shapes.
 *
 */
public class Rectangle {

  /**
   *
   * @param width The rectangle's width
   * @param height The rectangle's height
   */
  public Rectangle (double width, double height) {
     //TODO
  }
  /**
   * @return The rectangle's area.
   */
  public double getArea() {
    return 0; // TODO
  }

  /**
   * @return The rectangle's perimeter.
   */
  public double getPerimeter() {
    return 0; // TODO
  }

  /**
   * @return The rectangle's width.
   */
  public double getWidth() {
     return 0; // TODO
  }
  /**
   * @param width The rectangle's new width
   */
  public void setWidth(double width) {
      // TODO
  }

  /**
   * @return The rectangle's height.
   */
  public double getHeight() {
     return 0; // TODO
  }

  /**
   * @param height The rectangle's new height
   */
  public void setHeight(double height) {
      // TODO
  }
}

A:

First we define two instance variables width and height representing a Rectangle's corresponding two parameters width and height:

public class Rectangle {

  // Instance variables representing a rectangle's parameters
  private double width, height;
...
}

Next we allow for changing these two parameters:

public class Rectangle {

  // Instance variables representing a rectangle's parameters
  private double width, height;

...
  /**
   * @param width Changing the rectangle's width
   */
  public void setWidth(double w) {
      width = w;
  }

  /**
   * @param height Changing the rectangle's height
   */
  public void setHeight(double height) {
      this.height = height;
  }
...
}

Note the subtle implementation difference between setWidth(...) and setHeight(...):

setWidth(double w)

We use the formal parameter name w. Its name does not conflict with the instance variable name width being defined at class level. We can simply assign this value to our corresponding instance variable using width = w;.

setHeight(double height)

The method's formal parameter height shadows the instance variable's name being defined at class level. We need the this keyword in this.height = height to resolve the ambiguity.

Both ways are perfectly legal. The complete implementation including all remaining methods reads:

/**
 * Representing rectangular shapes.
 *
 */
public class Rectangle {

  // Instance variables representing a rectangle's parameters
  private double width, height;

  /**
   *
   * @param width The rectangle's width
   * @param height The rectangle's height
   */
  public Rectangle (double width, double height) {
     setWidth(width);
     setHeight(height);
  }
  /**
   * @return The rectangle's area.
   */
  public double getArea() {
    return width * height;
  }

  /**
   * @return The rectangle's perimeter.
   */
  public double getPerimeter() {
    return 2 * (width + height);
  }

  /**
   * @return The rectangle's width.
   */
  public double getWidth() {
     return width;
  }
  /**
   * @param width The rectangle's new width
   */
  public void setWidth(double w) {
      width = w;
  }

  /**
   * @return The rectangle's height.
   */
  public double getHeight() {
     return height;
  }

  /**
   * @param height The rectangle's new height
   */
  public void setHeight(double height) {
      this.height = height;
  }
}

exercise No. 97

Modeling circles

Q:

This exercise is very similar to Modeling geometry objects: Rectangles . With respect to the upcoming section on inheritance its presence will be justified later by the section called “Geometry classes reconsidered”.

We provide a corresponding class Circle dummy implementation:

package step1.dummy;

/**
 * A circle of given radius
 *
 */
public class Circle {

  /**
   * A new circle
   *
   * @param radius
   *          The desired radius.
   */
  public Circle(double radius) {
    // TODO
  }

  /**
   * @return The circle's area.
   */
  public double getArea() {
    return 0; // TODO
  }

  /**
   * @return The circle's perimeter.
   */
  public double getPerimeter() {
    return 0; // TODO
  }

  /**
   * @return The circle's radius.
   */
  public double getRadius() {
    return 0; // TODO
  }

  /**
   * @param radius
   *          Setting the circle's radius to a new value.
   */
  public void setRadius(double radius) {
    // TODO
  }
}

Instances of this class shall be usable in the following fashion:

public static void main(String[] args) {
  final Circle c = new Circle(2.3);

  System.out.println("Radius:" + c.getRadius());
  System.out.println("Perimeter:" + c.getPerimeter());
  System.out.println("Area:" + c.getArea());

  // Changing the circle's radius to a different value
  c.setRadius(4.7);

  System.out.println("Radius:" + c.getRadius());
  System.out.println("Perimeter:" + c.getPerimeter());
  System.out.println("Area:" + c.getArea());
}

Hint: Obviously you'll have to define an instance variable within Circle to keep track of its current radius value. All methods mentioned above simply depend on this single value.

A:

We define an instance variable radius inside our class Circle:

public class Circle {

  private double radius;
...
}

Next we implement our method to change a circle's radius:

public void setRadius(double r) {
  radius = r;
}

Note that we have chosen a different value for the method's formal radius parameter to be r rather than radius. Many people prefer to use radius here making it easier for a programmer to recognize the expected name in the generated Javadoc:

public void setRadius(double radius) {
  this.radius = radius;
}

This requires the usage of the this keyword to distinguish the formal parameter in setRadius(double radius) from the instance variable previously being defined within our class Circle. In other words: We have to resolve a name shadowing conflict.

The rest of the implementation is (quite) straightforward. A complete class reads:

package step1;

/**
 * A circle of given radius
 *
 */
public class Circle {

  private double radius;

  /**
   * A new circle
   * @param radius The desired radius.
   */
  public Circle(double radius) {
    setRadius(radius);
  }

  /**
   * @return The circle's area.
   */
  public double getArea() {
    return radius * radius * Math.PI;
  }

  /**
   * @return The circle's perimeter.
   */
  public double getPerimeter() {
    return 2 * Math.PI * radius;
  }

  /**
   * @return The circle's radius.
   */
  public double getRadius() {
    return radius;
  }

  /**
   * @param radius Setting the circle's radius to a new value.
   */
  public void setRadius(double radius) {
    this.radius = radius;
  }
}

exercise No. 98

Adding translations and SVG export.

Q:

We want to add more features to our Circle and Rectangle classes:

Translations

Add two more instance variables x and y and corresponding setter methods to account for a shape's translation vector with respect to the origin (0,0). The following hint may be helpful:

/**
 * @param x The circle's x center coordinate value
 */
public void setX(double x) {
  // TODO
}
/**
 * @param y The circle's y center coordinate value
 */
public void setY(double y) {
  // TODO
}

You may as well extend the constructors of Rectangle and Circle to accept center coordinates as well:

public class Rectangle {

...
   /**
    * Rectangle having center coordinates x, y, width and height.
    *
    * @param x The rectangle center's x-coordinate
    * @param y The rectangle center's y-coordinate
    * @param width The rectangle's width
    * @param height The rectangle's height
    */
   public Rectangle(double x, double y, double width, double height) {
     ...
   }
  ...
}
public class Circle {
   ...

   /**
    * Circle having center coordinates x, y and radius r.
    *
    * @param x The circle center's x-coordinate
    * @param y The circle center's y-coordinate
    * @param radius The circle's radius
    */
   public Circle(double x, double y, double radius) {
     ...
   }
  ...
}
SVG export

We would like Rectangle and Circle instances to be visualized as SVG graphics. SVG Examples provides editor samples both for circles and rectangles. Add a method void writeSvg() to both of your classes which allows for SVG code being written to standard output. Use System.out.println(...) calls to create the desired SVG output. You may need \" to escape double quotes as in the subsequent example or use single attribute quotes instead:

System.out.println("<rect width=\"20\"" ...

The following code snippet may serve to illustrate the intended use of void writeSvg():

public class Driver {

  public static void main(String[] args) {

    System.out.println("<!DOCTYPE html><html><body>");
    System.out.println("  <svg width='300' height='200' >");

    // Draw a rectangle as SVG
    final Rectangle r = new Rectangle(5, 4);
    r.setX(2);
    r.setY(1);
    r.writeSvg();

    // Draw a circle as SVG
    final Circle c = new Circle(3);
    c.setX(3);
    c.setY(1);
    c.writeSvg();
    System.out.println("  </svg >");
    System.out.println("</body></html>");
  }
}

Implement the method void writeSvg() in both classes Rectangle and Circle. The following sample export is intended for 300x200 pixel requiring to scale e.g. the above circle's radius of three by a factor of 20 resulting in an effective <circle r='60' .../> value. This scaling is being required for all parameters:

<!DOCTYPE html>
<html>
  <body>
    <svg width='300' height='200' >
      <rect width='100.0' height='80.0' x='40.0' y='20.0'
            style='fill:rgb(0,255,0);stroke-width:3;stroke:rgb(0,0,0)'/>
      <circle r='60.0' cx='60.0' cy='20.0'
            style='fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)'/>
      </svg >
  </body>
</html>

You may copy this output into a file svg.html. A web browser should visualize this output as:

A:

public class Rectangle {

  private double x, y, width, height;
 ...
  /**
   * @param x The rectangle's x center coordinate value
   */
  public void setX(double x) {
    this.x = x;
  }
  /**
   * @param y The rectangle's y center coordinate value
   */
  public void setY(double y) {
    this.y = y;
  }

public void writeSvg() {
    final int scale = 20;
    System.out.println(
        "<rect width='" + scale * width +"' height='" + scale * height +
        "' x='" + scale * x + "'" + " y='" + scale * y + "'" +
        "' style='fill:rgb(0,255,0);stroke-width:3;stroke:rgb(0,0,0)'/>");
  }
}
public class Circle {

  double x, y, radius;
...

  /**
   * @param x The circle's x center coordinate value
   */
  public void setX(double x) {
    this.x = x;
  }
  /**
   * @param y The circle's y center coordinate value
   */
  public void setY(double y) {
    this.y = y;
  }

public void writeSvg() {
  final int scale = 20;

    System.out.println(
        "<circle r='" + scale * radius +
        "' cx='" + scale * x + "'" + " cy='" + scale * y +
        "' style='fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)'/>");

  }
}

exercise No. 99

Extending the employee example.

Q:

Extend the Employee example from chapter 4 of [Kurniawan] by adding two methods:

  • /**
     * Raise the employee's salary by the given percentage.
     *
     * Example: If the current annual salary is 30000 € then
     * raising by 2,5% will result in 30750 €
     *
     * @param percentage Raise the current salary by this percentage.
     *
     */
    public void raiseSalary(double percentage) {
      // TODO: implement me!
    }
  • /**
     * Print the employee's current state to standard output like e.g.:
     *
     * <pre>Age:25
    Salary:30000.00</pre>
     */
    public void print() {
      // TODO: implement me!
    }

Run your implementation by a separate class Driver:

package company;

public class Driver {

   public static void main(String[] args) {

      final Employee jim = new Employee(25, 30_000.00);
      jim.print();

      System.out.println("Raising salary by 2%");

      jim.raiseSalary(2);
      jim.print();
   }
}

The expected output reads:

Age:25
Salary:30000.00
Raising salary by 2%
Age:25
Salary:30600.00

A:

/**
 * Raise the employee's salary by the given percentage.
 *
 * Example: If the current annual salary is 30000 € then
 * raising by 2,5% will result in 30750 €
 *
 * @param percentage Raise the current salary by this percentage.
 *
 */
public void raiseSalary(double percentage) {
  salary *= (1 + percentage / 100);
}

/**
 * Print the employee's current state to standard output like e.g.:
 *
 * <pre>Age:25
Salary:30000.00</pre>
*/
public void print() {
  System.out.println("Age:" + age);
  System.out.format("Salary:%6.2f\n", salary);
}

exercise No. 100

Refining access to an employee's attributes

Q:

The previous exercise featured two classes:

  • Employee defining an employee's attributes and methods.

  • Driver containing a main method for starting the application.

Currently both classes (hopefully!) reside in the same package company. We will assume the two attributes age and salary yet have no public, private or protected access modifiers :

package company;

public class Employee {
   int age;
   double salary;
 ...
}

Does the following code work?

package company;

public class Driver {

   public static void main(String[] args) {

      final Employee jim = new Employee(25, 30_000.00);

      jim.salary=40_000.00; // Raising jim's salary by direct member access

      jim.print();

   }
}

Modify your application by:

  • Creating a new package named model.

  • Move your Employee class from its current package company to model but leave your Driver class in its current package company. You may simply use your IDE's drag'n drop capabilities.

What do you observe? Explain this result. How do you solve the new problem?

Tip

Read the section on public, private, protected and default access level.

A:

Moving the Employee class from its company package to model changes its package declaration:

package company;

public class Employee {
   int age;
   double salary;
   ...
package model;

public class Employee {
   int age;
   double salary;
   ...

The movement also adds an additional import statement to your Driver class being required since both classes no longer reside in a common package:

package company;

public class Driver {

   public static void
     main(String[] args) {
      ...
package company;

import model.Employee;

public class Driver {

   public static void
       main(String[] args) {
      ...

Unfortunately a Driver class still residing in our company package will no longer compile due to a newly introduced access restriction:

package company;

public class Driver {

   public static void main(String[] args) {

      final Employee jim = new Employee(25, 30_000.00);

      jim.salary=40_000.00; // Compiler error:
                            // "The field Employee.salary is not visible"

      jim.print();

   }
}

This error message is in accordance with Table 4.1 from the Encapsulation and Access Control section of [Kurniawan]: The attributes age and salary have no access modifiers at all. Hence default access prohibits classes belonging to other packages accessing the attributes in question. More clearly: Members from class Driver have no permission to access either age or salary.

There are two possible ways to overcome this problem:

Granting access to alien classes (quick and dirty)

Raising access level from default to public thereby violating the principle of encapsulation:

public class Employee {
   public int age;
   public double salary;
 ...
Providing a so called setter method in our Employee class of access type public
package model;

public class Employee {
   int age;
   double salary;

   public void
     setSalary(double salary) {
      this.salary = salary;
   }
   ...
package company;

import model.Employee;

public class Driver {

  public static void
      main(String[] args) {

    final Employee jim =
      new Employee(25, 30_000.00);

      jim.setSalary(40_000.00);
 ...

The novice reader may question the advantage of the second approach: Alien classes have essentially the same means changing an employee's salary as with the first approach.

There is however one apparent benefit: Developers do have better control including bug tracking options on offer:

public void setSalary(double salary) {
  if (salary < 0) {
  System.err.println("This is odd: A salary may not become negative!" +
                     " Ask your union about minimum wages.");
  } else {
    this.salary = salary;
  }
}

exercise No. 101

File system representation

Q:

In the Employee exercise you moved the Employee class to a package model.

How are the corresponding Java source files Employee.java and Driver.java being represented in your file system? What about the generated byte code files Employee.class and Driver.class?

Tip

Use your OS file system explorer.

A:

Depending on your type of project (Java, Maven,...) both your .java source files and generated .class files will be organized below their respective entry level directories. The following typical layout depends on your Java development environment / IDE:

.java source files

Below folder src.

.class byte code files

Below folder target or bin.

Packages give rise to further sub directories both for source code and compiler generated byte code. The following example is a minor variation of our employee example. The model package has been refactored into company.model:

Figure 237. Employee example package hierarchy
 Project root
 ┣━━━┳ src 
    ┣━━━┳ company
   ...  ┣━━━ Driver.java ━━━━━━━━┓
        ┗━━━┳ model               compile
            ┗━━━ Employee.java ━━╋━━━┓
 ┣━━━┳ target                         
    ┣━━━┳ company                   
   ...  ┣━━━ Driver.class ◀━━━━━━   
        ┗━━━┳ model                  
            ┗━━━ Employee.class ◀━━━━
...

Folder src hosts source files e.g. classes like Employee.java.

Folder target hosts generated files. As an example Employee.class is being derived from Employee.java by compilation.


exercise No. 102

Your personal String class

Q:

This exercise is about using packages for resolving class name clashes. Usually you won't actually define a class String of your own next to java.lang.String.

Define your own String class internally using java.lang.String. Provide a suitable constructor and a public String toString() method just returning the internal java.lang.String instance allowing for the following snippet:

import my.personal.String;            // Own String class differing from java.lang.String

public class Driver {
  public static void main(...) {
    String john = new String("John");    // my.personal.String constructor accepting a java.lang.String argument
    System.out.println("Name: " + john); // john.toString() executes my.personal.String.toString()
    System.out.println(john.sayHello());
  }
}

The expected output reads:

Name: John
Hello 'John'

Tip

  1. Use a java.lang.String instance variable inside your private String class.

  2. Your class' constructor is bound to accept standard Java string literals. Using java.lang.String internally requires a fully qualified class name.

  3. As we'll see in Figure 465, “Overwriting toString() defining a String toString() method in a class allows for easy object to String conversion and thus for simply using System.out.println() for printing an object's state.

A:

We implement our private String class in a package de.hdm_stuttgart.mi.sd1.tooling:

package de.hdm_stuttgart.mi.sd1.tooling;

public class String { 

    final java.lang.String s; 

    public String(final java.lang.String s ) {
        this.s = s;
    }

    public java.lang.String toString()  {
        return s;
    }

    public java.lang.String  sayHello() {
        return "Hello '" + s + "', good morning!";
    }
}

Shadowing Java java.lang.String.

Using a standard Java java.lang.String instance internally. Fully qualified class name required resolving potential name clash.

Our constructor also accepts a standard Java java.lang.String instance.

This method will be called automatically when e.g using System.out.println(s) for printing an instance s.

Returning a java.lang.String instance.

There are basically two ways using de.hdm_stuttgart.mi.sd1.tooling.String and java.lang.String in the same scope:

Fully qualify java.lang.String:
package de.hdm_stuttgart.mi;

import de.hdm_stuttgart.mi.sd1.tooling.String;

public class Main {

    public static void main(java.lang.String  [] args) {
        String  john = new String("John");
        System.out.println("Name: " + john);
        System.out.println(john.sayHello());
    }
}

Qualifying is required to avoid shadowing by de.hdm_stuttgart.mi.sd1.tooling.String.

Due to the import statement this is actually de.hdm_stuttgart.mi.sd1.tooling.String.

Fully qualify de.hdm_stuttgart.mi.sd1.tooling.String:

Basically this variant is about mutually exchanging java.lang.String and de.hdm_stuttgart.mi.sd1.tooling.String:

package de.hdm_stuttgart.mi;

public class Main {

    public static void main(String  [] args) {
        de.hdm_stuttgart.mi.sd1.tooling.String  john =
                new de.hdm_stuttgart.mi.sd1.tooling.String("John");
        System.out.println("Name: " + john);
        System.out.println(john.sayHello());
    }
}

A Java standard java.lang.String instance.

In order not to override the implicit import java.lang.String we have to fully qualify our own de.hdm_stuttgart.mi.sd1.tooling.String class.