How an Object Will Call Tostring Method Implicitly

Why does this Java code implicitly calls toString() method?

System.out is a PrintStream instance that is a static member of System. The PrintStream class has a function println() that accepts an argument of type Object. That function, in Open JDK, looks like the following:

public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}

And if you look at String.valueOf(), which accepts an argument of type Object, you can see:

public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}

There is no magic. It's just a Java class that calls toString on objects.

Further Reading

  • Take a look at the docs for the PrintStream class: https://docs.oracle.com/javase/7/docs/api/java/io/PrintStream.html

Explicit vs implicit call of toString

There's little difference. Use the one that's shorter and works more often.

If you actually want to get the string value of an object for other reasons, and want it to be null friendly, do this:

String s = String.valueOf(obj);

Edit: The question was extended, so I'll extend my answer.

In both cases, they compile to something like the following:

System.out.println(new StringBuilder().append("obj: ").append(obj).toString());

When your toString() is implicit, you'll see that in the second append.

If you look at the source code to java, you'll see that StringBuilder.append(Object) looks like this:

public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}

where String.valueOf looks like this:

public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}

Now, if you toString() yourself, you bypass a null check and a stack frame and go straight to this in StringBuilder:

public StringBuilder append(String str) {
super.append(str);
return this;
}

So...very similar things happens in both cases. One just does a little more work.

How toString() is automatically call inside println()

Short answer: public frog1.toString() method call is used inside System.out.println(Object x) call stack.

But how? Let's find it out together :)

Take a look at the PrintStream class (which instance is used as System.out field value by default) source code and its println implementation that accepts Object argument:

public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}

And the String's valueOf method for argument with Object type is:

public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}

obj is frog1 in your case, its toString() method is called and returns "Hello" String instance for the console output)

Java implicit call of toString() when using the this keyword

Because that's what happens when you use the String concatenation operator (+).

It calls the toString() method of the object being added (which is guanateed to be there since it's defined in Object).

In your case, that's the current object (this) so you get this.toString() called. And because you've overriden toString() in your class, you get the result of that.

Edit to add: Note that there's no difference between + this and + this.toString(); you'll end up with the same result.

Specifically, this is covered by section 15.18.1 of the JLS

If only one operand expression is of type String, then string conversion (§5.1.11) is performed on the other operand to produce a string at run time.

And §5.1.11 states:

...

Now only reference values need to be considered:

If the reference is null, it is converted to the string "null" (four
ASCII characters n, u, l, l).

Otherwise, the conversion is performed as if by an invocation of the
toString method of the referenced object with no arguments; but if the
result of invoking the toString method is null, then the string "null"
is used instead.

Implicitly calling a method in a class from main

Java calls toString when you use + on a String and an object.

So your

System.out.println("Inizio: " + inizio + "\n" + "Fine: " + fine);

is the same as

System.out.println("Inizio: " + inizio.toString() + "\n" + "Fine: " + fine.toString());

except that if inizio or fine is null, the first won't give you an error (you'll see null in the string instead) but the second will.

From the JLS's section on the String Concatenation operator:

If only one operand expression is of type String, then string conversion (§5.1.11) is performed on the other operand to produce a string at run time.

which refers to the String Conversion section, which says (after discussing converting primitives to string):

...

Now only reference values need to be considered:

  • If the reference is null, it is converted to the string "null" (four ASCII characters n, u, l, l).

  • Otherwise, the conversion is performed as if by an invocation of the toString method of the referenced object with no arguments; but if the result of invoking the toString method is null, then the string "null" is used instead.

Why can class objects call the toString method if the class does not provide an implementation for the method?

Every Java class is a subclass of Object class.

Thus, by inheritance, all the operations available in Object class are available in every Java class. This includes toString() operation :).



Related Topics



Leave a reply



Submit