About toString:

by: Nicholas Duchon
Date: Jun 23, 2015

Outline:


public String toString () method

After looking up toString with google, I am really unhappy with the information I have found.

Creating a class:

First, what if we create a class and do not implement a toString method? Well, here's an example:

public class MyClass {
  public static void main (String args []) {
    MyClass x = new MyClass ();
    System.out.println (x);
  } // end main
} // end class MyClass

Output:

MyClass@70dea4e

NOTE: the System.out.println (x) - the parameter here is just the variable of type MyClass - and the Java system interprets this to mean that it should convert the instance x of the class MyClass to a string representation using MyClass's toString method. This is the way Java works.

Gruesome (you can skip this part if you don't understand it yet): So what is this? This is the default toString method from the Object class, the parent class of all classes in Java. It is not completely obvious, but the first field here is the name of the class. The second field is a kind of random number, the hash code for this class as it's loaded.

toString contract

What happens if we provide a toString method? NOTE: this is a special method that is:

I have seen at least one example (the tutorialspoint.com site) that talks as if toString (int) is the same kind of method. That is NOT the case, such a method does not override the method in Object, and will not be called in the case of code such as System.out.println (x).

Implementing a toString

Continuing - what if we implement a toString method, as per the requirements listed in the bullet points above? Here's an example (quite trivial):

public class MyClass {
  public String toString () {
    return "This is the String representation of a MyClass object";
  } // end method toString
 
  public static void main (String args []) {
    MyClass x = new MyClass ();
    System.out.println (x);
  } // end main
} // end class MyClass

Output:

This is the String representation of a MyClass object

Now, what if the class actually has interesting data fields? How might toString be used?

Example with instance fields

The point of toString is that it must return a String of some sort, and is typically used to return a useful representation of the instance variables of a class:

public class MyClass {
  int     a = 12;
  double  b = 4.554;
  char    c = '#';
  String  d = "Invincible";
  boolean e = true;
  String  f;
 
  public String toString () {
    return String.format (
         "%d, %f, %c, %s, %b, %s",
           a,  b,  c,  d,  e,  f);
  } // end method toString
 
  public static void main (String args []) {
    MyClass x = new MyClass ();
    System.out.println (x);
  } // end main
} // end class MyClass

Output:

12, 4.554000, #, Invincible, true, null

One key point here is that the code in main (System.out.println (x)) has NOT changed in all these examples - only the code inside the toString method has changed (and the new instance variables in the last example).

Alternate toString

Next, to understand just how flexible this approach is, the following toString implementation returns the same output as the one just above:

  public String toString () {
    String st = "";
    st += a + ", ";
    st += b + ", ";
    st += c + ", ";
    st += d + ", ";
    st += e + ", ";
    st += f;
    return st;
  } // end method toString

You may have noticed that this code does not explicity convert any of these primitive data types to a String. So, the Java system is in fact calling toString methods appropriate to each object. For example, the details work like this: a is an int, the system automatically converts this to an Integer object, and then calls the toString method in the Integer class. Another example of just how powerful the concepts of toString and method overriding are in Java.

As with all examples, you will get the most out of these if you experiment with them yourself.

More Examples:

There are more, and more interesting, examples of toString methods in many of the examples on the following pages:

Example with arrays.

I think you will start to understand a lot more about how toString might work with data structures in the following example. Here we are considering a 2D integer array with some numbers:

public class ArrayTestA {
  public static void main (String args []) {
    int n = 5, m = 3;
    int x [] [] = new int [n][m];
   
    for (int i = 0; i < x.length; i++)
      for (int j = 0; j < x[i].length; j++)
        x[i][j] = i*j - 5 * i + 12 * j;
   
    for (int [] r: x) {
      for (int v: r)
        System.out.printf ("%5d", v);
      System.out.println ();
    }  // end for each row

    System.out.println (java.util.Arrays.toString (x));
    System.out.println (java.util.Arrays.deepToString (x));
  } // end main
} // end class ArrayTestA

Output:

    0   12   24
   -5    8   21
  -10    4   18
  -15    0   15
  -20   -4   12
[[I@70dea4e, [I@5c647e05, [I@33909752, [I@55f96302, [I@3d4eac69]
[[0, 12, 24], [-5, 8, 21], [-10, 4, 18], [-15, 0, 15], [-20, -4, 12]]

Adding toString

The yellow hightlighted code is now calling the toString method of the ArrayTestB class, and it is that toString method which is walking through the instance variable x (the 2D array).

public class ArrayTestB {
  int x [] [];
 
  public ArrayTestB (int n, int m) {
    x = new int [n][m];
  
    for (int i = 0; i < x.length; i++)
      for (int j = 0; j < x[i].length; j++)
        x[i][j] = i*j - 5 * i + 12 * j;
  } // end int/int constructor
 
  public String toString () {
    String st = "";
    for (int [] r: x) {
      for (int v: r)
        st += String.format ("%5d", v);
      st += "\n";
    }  // end for each row
    return st;
 
} // end method toString
 
  public static void main (String args []) {
    ArrayTestB atb = new ArrayTestB (5, 3);
  
    System.out.println ("Arrays.toString:\n" + java.util.Arrays.toString (atb.x));
    System.out.println ("\nArrays.deepToString:\n" + java.util.Arrays.deepToString (atb.x));
    System.out.println ("\nArrayTestB toString:\n" + atb);
 
} // end main
} // end class ArrayTestB

OUTPUT:

Arrays.toString:
[[I@70dea4e, [I@5c647e05, [I@33909752, [I@55f96302, [I@3d4eac69]

Arrays.deepToString:
[[0, 12, 24], [-5, 8, 21], [-10, 4, 18], [-15, 0, 15], [-20, -4, 12]]

ArrayTestB toString:
    0   12   24
   -5    8   21
  -10    4   18
  -15    0   15
  -20   -4   12

next?


ND.