Overriding toString()

Figure 479. Printing a Shape's info Slide presentation
Code Output
final Shape shape =
     new Shape(2.0, 3.0); // Center coordinates
IO.println(shape); 
inherit.Shape@37d31475

Desired:

(2.0|3.0)

Figure 480. Overwriting toString() Slide presentation

Figure 481. Shape extending Object Slide presentation

Figure 482. Overriding toString() in class Shape. Slide presentation
Code
public class Shape {
  private int x, y;
    ...
  @Override public String toString() {
        return "(" + x + "|" + y + ")";
    }
}
IO.println(new Shape(2.0, 3.0));
Output
(2.0|3.0)

Figure 483. Logging Rectangle instances Slide presentation
Code
// Center coordinates (2|3), width==5 and height==7
final Rectangle r = new Rectangle(2.0, 3.0, 5.0, 7.0);
IO.println(r);
Output

Desired:

(2.0|3.0), width=5.0, height=7.0

Figure 484. Overriding toString() in Rectangle. Slide presentation
public class Rectangle extends Shape {
  private double width, height;
    ...
  @Override public String toString() {
    return super.toString()  +
      ", width=" + width + ", height=" + height; 
  } ...

The super keyword allows for calling the superclass Shape's toString() method inserting the (2.0|3.0) center coordinate.

Append class Rectangle's own width and height attribute values.


Figure 485. Rectangle extending Shape Slide presentation

Figure 486. Implementing Circle.toString() Slide presentation
Code
public class Circle extends Shape {
  private double radius;
    ...
  @Override public String toString() {
    return super.toString() + ", radius=" + radius;
  }
}
IO.println(new Circle(2.0, 3.0, 7.0));
Output
(2.0|3.0), radius=7.0

Figure 487. Shape inheritance hierarchy and toString() Slide presentation
Shape inheritance hierarchy and toString()

exercise No. 179

String vs. StringBuffer

Q:

Consider two StringBuffer instances:

Code Execution result
final StringBuffer
  a = new StringBuffer("test"),
  b = new StringBuffer("test");

IO.println(a.equals(b));
false

Strangely String instances behave differently:

Code Execution result
final String
  a = new String("test"),
  b = new String("test");

IO.println(a.equals(b));
true

Explain this different behaviour.

Tip

Take a closer look at the String and StringBuffer API regarding the toString() method.

A:

The String API reveals:

public boolean equals (Object anObject)
Compares this string to the specified object. The result is true if and only if the argument is
not null and is a String object that represents the same sequence of characters as this object.

Overrides: equals in class Object

Parameters:
anObject - The object to compare this String against

Returns:
true if the given object represents a String equivalent to this string, false otherwise

In a nutshell: The superclass Object.equals() method is being overridden: Two instances of String will be compared for equality character by character, i.e. by content as expected.

The StringBuffer does not override its parent classes Object.equals() method. Therefore comparing two of its instances results in:

public boolean equals (Object obj)
Indicates whether some other object is "equal to" this one.
...
Parameters:
obj - the reference object with which to compare.
Returns:
true if this object is the same as the obj argument; false otherwise.

The comparison is thus by object identity rather than by content.

exercise No. 180

Alternate implementation of opposite directions

Q:

Provide a different implementation of your opposite() from Compass direction neighbours based on values() and ordinal().

A:

We observe the following ordinal values:

public enum Direction {

  N(   0, "north"),         // 0
  NE( 45, "north by east"), // 1
  E(  90, "east"),          // 2
  SE(135, "south by east"), // 3
  S( 180, "south"),         // 4
  SW(225, "south by west"), // 5
  W( 270, "west"),          // 6
  NW(315, "north by west"); // 7
...
public Direction opposite() {
    switch (this) {
      case N: return S;   // 04
      case NE: return SW; // 15
      case E: return W;   // 26
      case SE: return NW; // 37
      case S: return N;   // 40
      case SW: return NE; // 51
      case W: return E;   // 62
      case NW: return SE; // 73
      ...

We are thus require implementing an integer shift of (0, 1, 2, 3, 4, 5, 6, 7)(4, 5, 6, 7, 0, 1, 2, 3) by four places:

public Direction opposite() {
   return values()[(ordinal() + 4) % 8];
}