The Connection Between 'System.Out.Println()' and 'Tostring()' in Java

The connection between 'System.out.println()' and 'toString()' in Java

System.out is a PrintStream. Printstream defines several versions of the println() function to handle numbers, strings, and so on. When you call PrintStream.println() with an arbitrary object as a parameter, you get the version of the function that acts on an Object. This version of the function

...calls at first String.valueOf(x) to get the printed object's string value...

Looking at String.valueOf(Object), we see that it returns

if the argument is null, then a string equal to "null"; otherwise, the value of obj.toString() is returned.

So, long story short, System.out.println(someObject) calls that object's toString() function to convert the object to a string representation.

If your object defines its own toString() function, then that is what will be called. If you don't provide such a function, then your object will inherit toString() from one of its parent classes. In the worst case, it will inherit Object.toString(). That version of toString() is defined to return

a string consisting of the name of the class of which the object is an instance, the at-sign character `@', and the unsigned hexadecimal representation of the hash code of the object.

Or, in other words:

getClass().getName() + '@' + Integer.toHexString(hashCode())

So, when you call System.out.println() on an object that doesn't define its own version of toString(), you might get the Object version which looks like "classname@someHexNumber".

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

Why System.out.println(new String(copyTo))?

There is no need for new String(copyTo) there. copyTo would suffice.

In general, you don't want to invoke println on an array. For example:

System.out.println(new int[]{1, 2, 3});

wouldn't print [1, 2, 3] or 123, but rather something like [I@243432. This is because there is no special overload for int[] (or other array types, except for char[]), so println(Object) is used. This invokes toString() on the parameter; but arrays don't have useful toString() implementations.

However, the PrintStream.println(char[]) method does work somewhat sensibly, and produces an output as if the char[] were converted to a String first (but note that the toString() method isn't used to produce this: no String is created from the array).

 System.out.println(new String(copyTo));
System.out.println(copyTo);

Output:

caffein
caffein

I suspect it's just an oversight/bug in the documentation that new String is used. I filed a bug report with Oracle to get it fixed.

How does System.out.print() work?

System.out is just an instance of PrintStream. You can check its JavaDoc. Its variability is based on method overloading (multiple methods with the same name, but with different parameters).

This print stream is sending its output to so called standard output.


In your question you mention a technique called variadic functions (or varargs). Unfortunately that is not supported by PrintStream#print, so you must be mistaking this with something else. However it is very easy to implement these in Java. Just check the documentation.


And if you are curious how Java knows how to concatenate non-string variables "foo" + 1 + true + myObj, it is mainly responsibility of a Java compiler.

When there is no variable involved in the concatenation, the compiler simply concatenates the string. When there is a variable involved, the concatenation is translated into StringBuilder#append chain. There is no concatenation instruction in the resulting byte code; i.e. the + operator (when talking about string concatenation) is resolved during the compilation.

All types in Java can be converted to string (int via methods in Integer class, boolean via methods in Boolean class, objects via their own #toString, ...). You can check StringBuilder's source code if you are interested.


UPDATE: I was curious myself and checked (using javap) what my example System.out.println("foo" + 1 + true + myObj) compiles into. The result:

System.out.println(new StringBuilder("foo1true").append(myObj).toString());

How to use the toString method in Java?

From the Object.toString docs:

Returns a string representation of the
object. In general, the toString
method returns a string that
"textually represents" this object.
The result should be a concise but
informative representation that is
easy for a person to read. It is
recommended that all subclasses
override this method.

The toString method for class Object
returns a string consisting of the
name of the class of which the object
is an instance, the at-sign character
`@', and the unsigned hexadecimal
representation of the hash code of the
object. In other words, this method
returns a string equal to the value
of:

getClass().getName() + '@' + Integer.toHexString(hashCode())

Example:

String[] mystr ={"a","b","c"};
System.out.println("mystr.toString: " + mystr.toString());

output:- mystr.toString: [Ljava.lang.String;@13aaa14a

Difference between printStackTrace() and toString()

No, there is an important difference! Using toString, you only have the type of the exception and the error message. Using printStackTrace() you get the whole stacktrace of an exception, which is very helpful for debugging.

Example of System.out.println(toString()):

java.io.FileNotFoundException: yourFile.txt (The system cannot find the file specified)

Example of printStackTrace():

java.io.FileNotFoundException: yourFile.txt (The system cannot find the file specified)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.(FileInputStream.java:106)
at java.io.FileReader.(FileReader.java:55)
at ReadFromFile.main(ReadFromFile.java:14)

To make a string of the whole stacktrace, I usually use this method:

public static String exceptionStacktraceToString(Exception e)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
e.printStackTrace(ps);
ps.close();
return baos.toString();
}

Also note that simply calling toString() simply returns a string, and won't print anything out.

toString() method within System.out.println() a double call?

No, it is not more efficient -- precisely because of the overload that you mentioned. Moreover, a call of toString on a String is extremely quick, so even without an overload the difference would not be measurable.

However, your professor is right about not making the call like System.out.println(object.toString());, but the reason is different: since the call is unnecessary, the readers of your code may get confused.

I want to print an array with a toString() method in java, but without brackets and commas (so, not with Arrays.toString())

Change array.toString() to toString(array). Also your method needs to be static because main method is static. And if you want to use it in print statement, then it should return something. That's why I have changed the return type of your method to String:

public static String toString(int[] num) { 
String s = "";
for (int index = 0; index < num.length; index++) {
s += num[index];
}
return s;
}

public static void main(String[] args) {
//test negative number, output should be -10000000
int largeNum1[] = {-2, 0, 0, 0, 0, 0, 0, 0};
int largeNum2[] = {1, 0, 0, 0, 0, 0, 0, 0};
int numSize1 = (largeNum1.length + largeNum2.length) + 1;
int[] sum1 = new int[numSize1];
int[] answer1 = sumNumbers(largeNum1, largeNum2, sum1);
System.out.println((toString(largeNum1)) + " + " + (toString(largeNum2)) + " = " + (toString(answer1)));
}

How do I read / convert an InputStream into a String in Java?

A nice way to do this is using Apache commons IOUtils to copy the InputStream into a StringWriter... something like

StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer, encoding);
String theString = writer.toString();

or even

// NB: does not close inputStream, you'll have to use try-with-resources for that
String theString = IOUtils.toString(inputStream, encoding);

Alternatively, you could use ByteArrayOutputStream if you don't want to mix your Streams and Writers



Related Topics



Leave a reply



Submit