Saturday, April 23, 2011

Usage of overriding toString method


One of the standard methods defined in java.lang.Object is toString.  This method is used to obtain a string representation of an object.  We can (and normally should) override this method for classes that we write.

Let's first consider some sample code:

class MyPoint
{

       private int x, y;

       public MyPoint(int x, int y)
       {

           this.x = x;
           this.y = y;
       }
}

public class TSDemo1
{

          public static void main(String args[])
          {          // use default Object.toString()

                 MyPoint mp = new MyPoint(37, 47);      
                 System.out.println(mp);

                 // same as previous, showing the
                 // function of the default toString()

                 System.out.println(mp.getClass().getName() + "@" + Integer.toHexString(mp.hashCode()));
          }
}

output:
MyPoint@111f71
MyPoint@111f71


The TSDemo1 program defines a class MyPoint to represent X, Y points.  It does not define a toString method for the class.  The program creates an instance of the class and then prints it.  In fact, the library methods such as System.out.println know nothing about the MyPoint class or its objects.  So, the println calls the java.io.PrintStream.print(Object) method, which then calls the String.valueOf method.  The String.valueOf method is very simple:

public static String valueOf(Object obj)
{

      return (obj == null) ? "null" : obj.toString();
}

When println is called with a MyPoint object reference, the String.valueOf method converts the object to a string.  String.valueOf first checks to make sure that the reference is not null.  It then calls the toString method for the object.  Since the MyPoint class has no toString method, the default one in java.lang.Object is used instead.  The default toString method actually return the name of the class, an "@", and the hex version of the object's hashcode are concatenated into a string and returned.  The default hashCode method in Object is typically implemented by converting the memory address of the object into an integer.  So the results might vary from those shown above.

We can write our own toString method as shown below.

class MyPoint
{

      private int x, y;

      public MyPoint(int x, int y)
     {

          this.x = x;
          this.y = y;
      }

      public String toString()
      {

              return "X=" + x + " " + "Y=" + y;
      }

     public int getX()
    {

                return x;
    }

    public int getY()
    {

            return y;
    }
}

public class TSDemo2
{

       public static void main(String args[])
       {

                          MyPoint mp = new MyPoint(37, 47);
                         // call MyPoint.toString()
                         System.out.println(mp);

                        // get X,Y values via accessor methods
                        int x = mp.getX();
                        int y = mp.getY();
                        System.out.println(x);
                        System.out.println(y);
      }
}

The output is:
X=37 Y=47
37
47


This example adds some descriptive text to the output format, and defines a couple of accessor methods to get at the X, Y values.  In general, when we write a toString method, the format of the string that is returned should cover all of the object contents.  Our toString method should also contain descriptive labels for each field.  And there should be a way to get at the object field values without having to pick apart the string.  Note that using "+" within toString to build up the return value is not necessarily the most efficient approach.  We might want to use StringBuffer instead.

The toString() method was implemented for the following classes to know the content of the object.

HashMap names = new HashMap();
names.put(new Integer(5), "RAM");
names.put(new Integer(1), "KRIS");
names.put(new Integer(4), "BHANU");
names.put(new Integer(8), null);
System.out.println(names);


output: {4=BHANU, 8=null, 1=KRIS, 5=RAM}


ArrayList aNames = new ArrayList();
aNames.add("SWATI");
aNames.add("ANAND");
aNames.add(null);
aNames.add("MAJNU");
System.out.println(aNames);

output: [SWATI, ANAND, null, MAJNU]

For more information about using toString methods, see item 9, Always override toString, in "Effective Java Programming Language Guide" by Joshua Bloch.