toString and null
Let's print a whole point: System.out.println(p);. You would like to see the coordinates, but the program prints something like this:
Point@1dbd16a6This is the class name, the @ sign and a hexadecimal number the JVM gave the object. Yours may be different: the number depends on the JVM and on how the program is started. It is as if you asked someone to describe a house and got the name of the blueprint and the number on its plate.
When println gets an object, it asks the object to describe itself as a string: it calls the object's method toString. Every object has such a method, but the standard one returns exactly the string Point@…. Your own class can describe itself.
Your own toString method
Let's add a method to the class Point that returns the coordinates:
public class Main {
public static void main(String[] args) {
Point p = new Point();
System.out.println(p); // (0, 0)
}
}
class Point {
int x;
int y;
public String toString() {
return "(" + x + ", " + y + ")";
}
}Let's go through the program step by step:
- The class
Pointnow has a methodtoStringwith the headerpublic String toString(). - The method builds a string from the coordinates:
"(" + x + ", " + y + ")". System.out.println(p)callsp.toString()by itself and prints the result:(0, 0).
What matters about toString:
- the header is written exactly so: the name
toString, no parameters, the resultString; publicis required: without it the program does not compile;- such a method replaces the standard
toString, and how this replacement works and why@Overrideis written above it are covered in the theme on inheritance.
Adding an object to a string with + calls its toString too:
p.x = 3;
System.out.println("p = " + p); // p = (3, 0)The null reference
A variable of type Point can hold a special reference, null: a slip with no address on it. It leads to no object. A field of type String or Point that was given nothing holds null, and you can put it into a variable yourself:
Point r = p;
p = null;
System.out.println(r); // (3, 0)
System.out.println(p); // null
System.out.println(p == null); // trueLine by line:
Point r = p;is a second slip with the address of the same point.p = null;erases the address only on the slipp. The point itself stays where it is.rstill leads to it, andprintlnprints(3, 0).println(p)prints the wordnull: there is no object, nothing to describe.p == nullgivestrue. This is how you check that there is an object before working with it.
println and + handle null themselves and write the word null. But you cannot take a field or a method through such a variable: p.toString() with p equal to null stops the program.
Here the slip picture is not exact. With a blank slip, a person goes nowhere and gets back to their business, while Java stops the program at an attempt to go to a blank address.
Common mistake
A field is read through a variable that holds null:
Point p = null;
System.out.println(p.x); // ✗Exception in thread "main" java.lang.NullPointerException: Cannot read field "x" because "<local1>" is nullThe program compiles: the compiler does not track whether a variable holds null. The JVM finds the error when it reaches p.x: there is no object, so there is nowhere to take the field x from. The JVM throws a NullPointerException and stops the program. Interviewers ask about it all the time: it is one of the most common exceptions in Java.
The message tells you what happened:
Cannot read field "x": the fieldxcould not be read;because "<local1>" is null: because the variable holdsnull;- the next line of output,
at Main.main(…), names the method and the line number.
Why <local1> and not p? java Main.java keeps no variable names, so the JVM refers to p by number: it is the first local variable after args. If you compile the program with javac -g Main.java and run java Main, the message gives the name: because "p" is null.
To avoid the error, create the object before reading it, Point p = new Point();, or check the reference: if (p != null).
Key points
println(p)and"p = " + pcallp.toString(); your ownpublic String toString()describes the object as a string, while the standard one printsPoint@….nullis a reference that leads to no object;p = nullerases the reference only inp.- A field or a method through
nullis aNullPointerExceptionat run time, not a compile error. - The exception's message says what failed and which variable was
null; withoutjavac -ga number stands in place of the name, such as<local1>.