Overriding toString()

Figure 471. Printing a Shape's info Slide presentation
Code Output
package inherit;

public class Run {
  
  public static void main(String[] args) {
  final Shape shape =
     new Shape(2.0, 3.0); // Center coordinates
    System.out.println(shape); 
inherit.Shape@37d31475

Desired:

(2.0|3.0)

Figure 472. Overwriting toString() Slide presentation

Figure 473. Shape extending Object Slide presentation

Figure 474. Logging Rectangle instances Slide presentation
Code Output
final Rectangle r =                   // Center coordinates,
  new Rectangle(2.0, 3.0, 3.0, 4.0);  // width and height
System.out.println(r);
(2.0|3.0)

Desired:

Rectangle at (2.0|3.0), width= 3.0, height=4.0

Figure 475. Override toString() in class Rectangle. Slide presentation
public class Rectangle extends Shape {
  @Override public String toString() {
    return "Rectangle at " + 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 476. Rectangle extending Shape Slide presentation

Figure 477. Implementing Circle.toString() Slide presentation
public class Circle extends Shape {
  /**
   * Creating a circle of given center and radius
   * @param x Center's x component.
   * @param y Center's y component.
   * @param radius The circle's radius.
   */
  public Circle(double x,double y, double radius) {
    super(x, y);
    this.radius = radius;
  }
  @Override public String toString() {
    return "Circle at " + super.toString() +", radius= " + radius;
  }
  private double radius;
}

Figure 478. Shape and toString() Slide presentation
Shape and toString()

exercise No. 163

String vs. StringBuffer

Q:

Consider two StringBuffer instances:

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

System.out.println(a.equals(b));
false

Strangely instances of String behave differently:

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

System.out.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: Two instances of String will be compared for equality character by character. The superclass Object.equals() method is being overridden.

In class StringBuffer we do not find any equals() method. Thus Object.equals() is not being overridden. When comparing two instances of StringBuffer effectively Object.equals() will be executed. Its API reveals:

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.

Thus two instances of StringBuffer will be compared for object identity rather than representing the same string value.

exercise No. 164

Alternate implementation of opposite directions

Q:

Provide a different implementation of your opposite() from Compass direction neighbours . Follow https://stackoverflow.com/questions/5678309/illegal-forward-reference-and-enums#answer-49409377. Start by investigating both 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;   // 0 --> 4
      case NE: return SW; // 1 --> 5
      case E: return W;   // 2 --> 6
      case SE: return NW; // 3 --> 7
      case S: return N;   // 4 --> 0
      case SW: return NE; // 5 --> 1
      case W: return E;   // 6 --> 2
      case NW: return SE; // 7 --> 3
      ...

We are thus left implementing an integer shift (0, 1, 2, 3, 4, 5, 6, 7) to (4, 5, 6, 7, 0, 1, 2, 3):

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