Constructors

Figure 252. Creating and initializing rectangles Slide presentation Create comment in forum
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 253. Defining a constructor Slide presentation Create comment in forum
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 229, “Method definition syntax ” but:

No return type declaration.

Constructor's name equals class name.

Figure 254. Constructor syntax Slide presentation Create comment in forum
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 MyClass("xyz").


Figure 255. Constructors Slide presentation Create comment in forum
  • 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.


Figure 256. Multiple constructors by overloading Slide presentation Create comment in forum
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 constructors by overloading

Figure 257. Constructor calls within constructor Slide presentation Create comment in forum
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 258. Instances by overloaded constructors Slide presentation Create comment in forum
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 259. No constructor vs. default constructor Slide presentation Create comment in forum
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;
}

Figure 260. Absent default constructor Slide presentation Create comment in forum
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;
  }
}
// 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. 87

Modeling geometry objects: Rectangles Create comment in forum

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 heigth The rectangle's height
   */
  public Rectangle (double width, double heigth) {
     //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 width 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 heigth 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 width The rectangle's new height
   */
  public void setHeight(double height) {
      this.height = height;
  }
}

exercise No. 88

Modeling circles Create comment in forum

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 {

  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 {

  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. 89

Adding translations and SVG export. Create comment in forum

Q:

We want to add more features to tour 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. 90

Extending the employee example. Create comment in forum

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. 91

Refining access to an employee's attributes Create comment in forum

Q:

In Extending the employee example. you had two classes:

  • A class Employee defining an employee's attributes and methods.

  • A class Driver containing a main method to start 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 just 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 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. 92

File system representation Create comment in forum

Q:

In Refining access to an employee's attributes you moved the Employee class to a package model.

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

Tip

Use your OS's 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 bin.

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

Figure 261. Package hierarchy of the employee example
Package hierarchy of the employee example

exercise No. 93

Constructors variable names and this. Create comment in forum

Q:

Currently our constructor is being implemented as:

public Employee(int ageValue, double salaryValue) {
  age = ageValue;
  salary = salaryValue;
}

This imposes problems with respect to proper documentation. A developer will try to choose reasonable variable names clearly indicating the desired purpose like age and salary.

But the ratio for choosing ageValue and salaryValue originates from the need to avoid shadowing of variable names. From the viewpoint of code comprehensibility we prefer:

public Employee(int age, double salary) {
                    // Compiler warnings:
   age = age;       // The assignment to variable age has no effect
   salary = salary; // The assignment to variable salary has no effect
}

This compiles correctly but yields an unexpected result: The constructor variables int age and int salary will be assigned to themselves as being indicated by a corresponding compiler warning. More important their values don't make it to the age and salary attributes being defined on class level.

Apparently we are missing something. Explain these two compiler warnings. How can the underlying conflict be resolved?

Tip

Read the section in [Kurniawan] about the this keyword.

A:

When choosing public Employee(int age, double salary) we have two sets of variables (age, salary) in two different conflicting scopes:

Class scope:
public class Employee {
   public int age;
   public double salary;
  ...
}
Method's formal parameter list scope:
public Employee(int age, double salary) {.../* Constructor's method body */}

Within the constructor's method body the parameter list scope will take precedence over class scope. Thus the assignment age = age will assign the constructor's argument age to itself rather than assigning it to the instance variable age being defined within class scope.

We may explicitly resolve this scope conflict in our favour by qualifying the instance variables age and salary using their respective scope being represented by the this keyword:

public Employee(int age, double salary) {
  // The "this" keyword refers to class scope
  this.age = age;
  this.salary = salary;
}

exercise No. 94

Your personal String class Create comment in forum

Q:

This exercise is about using packages for resolving class name clashes.

Define your own String class having a suitable constructor and a public String toString() method allowing for the following snippet:

public static void main(...) {
  String john = new String("John");
  System.out.println("Name: " + john);
  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.

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  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.

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  s = new String("John");
        System.out.println(s.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:
package de.hdm_stuttgart.mi;

public class Main {

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

A Java standard 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.