Displaying objects

Displaying objects #

The class Object #

Java has a native class called Object with 11 instance methods. Every Java class implicitly extends Object, including user-defined classes. Therefore any Java class inherits these methods.

The method toString #

toString is one of the methods of the class Object. Here is (part of) its specification:

/** Returns a string representation of the object.
 * In general, the toString method returns a string that "textually represents" this object.
 */
public String toString();

This is the preferred way to display information about an object. For instance, the debugger of your IDE probably relies on this method to display a string that represents an object.

This method is also called by many (native or not) methods and operators. For instance, the following program

Unicorn myUnicorn = new Unicorn("green");
System.out.println(myUnicorn);
String message = "Hello " + myUnicorn;

is equivalent to

Unicorn myUnicorn = new Unicorn("green");
System.out.println(myUnicorn.toString());
String message = "Hello " + myUnicorn.toString();

Overriding toString #

The default implementation of toString (in the class Object) displays very little information about the object:

public String toString() {
    return getClass().getName() + "@" +
      Integer.toHexString(hashCode());
}

Warning. The output of hashCode() in this example is not the reference (a.k.a. “memory address”) of the object.

So a common practice consists in overriding toString. For instance, here is a possible implementation of the method toString within a class Unicorn:

public class Unicorn {

    String color;
    int health;

    ...

    @Override
    public String toString() {
        return "Unicorn{" +
            "color=" + color + ", " +
            "health=" + health +
        "}";
    }
}

Or better (if MobileUnit is a superclass of Unicorn and Butterfly, as in our previous example):

public class MobileUnit extends Unit {

    String color;

    ...

    @Override
    public String toString() {
        return getClass().getName() + "{" +
            "color=" + color + ", " +
            "health=" + health +
        "}";
    }
}

Hint. Your IDE can generate such a method.

Recursion #

A naive implementation of toString (e.g. generated by an IDE) may have unexpected effects.

Consider an implementation of our game where units (on each side of the board) are grouped by column. This implementation may use a class Column to represent a column and the adjacent one(s), as follows:

public class Column {

    Unit[] units;
    // null if this is the left-most column
    Column leftAdjacentColumn;
    // null if this is the right-most column
    Column rightAdjacentColumn;

    public Column(Unit[] units){
        this.units = units;
    }

    @Override
    public String toString() {
        return "Column{" +
            "units=" + units + ", " +
            "left=" + leftAdjacentColumn + ", " +
            "right=" + rightAdjacentColumn +
        "}";
    }
}

Then a board may be created as follows:

Unit[] a1 = new Unit[]{ new Unicorn("green") };
Column c1 = new Column(a1);
Unit[] a2 = new Unit[]{ new Butterfly("yellow") };
Column c2 = new Column(a2);
c1.rightAdjacentColumn = c2;
c2.leftAdjacentColumn = c1;

System.out.println(c1);

There is an issue with this program. Can you identify it?

The program does not terminate, because toString is (implicitly) recursive, and each of the two columns refers to the other.