How does System.out.print() work?
Asked Answered
A

9

27

I have worked with Java for a quite a long time, and I was wondering how the function System.out.print() works.

Here is my doubt:

Being a function, it has a declaration somewhere in the io package. But how did Java developers do that, since this function can take in any number of arguments and any argument types no matter how they are arranged? e.g:

System.out.print("Hello World");
System.out.print("My name is" + foo);
System.out.print("Sum of " + a + "and " + b + "is " + c);
System.out.print("Total USD is " + usd);

No matter what is the datatype of variables a, b, c, usd, foo or how they are passed, System.out.print() never throws an error.

For me, I have never worked on any project where the requirement was like this. Provided, if I get a requirement like this, I really don't know how to solve it.

Can anyone explain to me how it's done?

Assay answered 15/6, 2013 at 7:37 Comment(4)
There is an error, because System.out.print (PrintWriter) certainly does not support your lines 2 to 4, it has no such a method.Barnaba
System.out.print() never throws an error Really? Well, in your example, it does, it throws an error on every line but the first. Commas are not accepted in System.out.print(), as commas are used to separate different parameters and System.out.print() accepts 1 parameter.. Concatenation between strings is done by using the + operator.Farhi
is , a typo? instead of +?Screwed
Java documentation would certainly answer that question for you and uncle google probably knows.Rumsey
M
30

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());
Mezzotint answered 15/6, 2013 at 7:42 Comment(4)
To be complete one could add that while argument overloading is allowed, return value overloading isn't. +1.Gamble
I don't see why this answer was upvoted, because it is wrong. system.out.print doesn't take a variable number of arguments, it simply takes a single string.Fellner
@Fellner maybe because I am saying that it does not support it? Please read before downvoting.Mezzotint
so it has nothing to do with : System being a framework, out being a class and println being a method right? :)Juxon
F
3

Even though it look as if System.put.print...() take a variable number of arguments it doesn't. If you look closely, the string is simply concatenated and you can do the same with any string. The only thing that happens is, that the objects you are passing in, are implicitily converted to a string by java calling the toString() method.

If you try to do this it will fail:

int i = 0;
String s = i;
System.out.println(s);

Reason is, because here the implicit conversion is not done.

However if you change it to

int i = 0;
String s = "" + i;
System.out.println(s);

It works and this is what happens when using System.put.print...() as well.

If you want to implement a variable number of arguments in java to mimimc something like C printf you can declare it like this:

public void t(String s, String ... args)
{
    String val = args[1];
}

What happens here is that an array of Strings is passed in, with the length of the provided arguments. Here Java can do the type checking for you.

If you want truly a printf then you have to do it like this:

public void t(String s, Object ... args)
{
    String val = args[1].toString();
}

Then would you have to cast or interpret the arguments accordingly.

Fellner answered 15/6, 2013 at 7:58 Comment(0)
S
3

It is a very sensitive point to understand how System.out.print works. If the first element is String then plus(+) operator works as String concate operator. If the first element is integer plus(+) operator works as mathematical operator.

public static void main(String args[]) {
    System.out.println("String" + 8 + 8); //String88
    System.out.println(8 + 8+ "String"); //16String
}
Spieler answered 4/4, 2017 at 7:27 Comment(0)
N
1

Evidently, the compiler was made in a confusing way although the compiler developers thought they added some smartness. The true smartness they should really add is to look entire argument and interpret + operator consistently. For example, System.out.println(1+2+"hello"+3+4); should output 3hello7 instead of 3hello34

Ningsia answered 7/9, 2017 at 12:43 Comment(1)
What makes you say 3hello34 is inconsistent? Addition is left-to-right associative, with each operation having equal precedence. You're arguing that the 3+4 should be higher precedence than the addition that precedes it, which would be inconsistent. That's like saying that 1 + 2 / 0 + 3 should equal 1 instead of being a division-by-zero error. (Granted, string concatenation could have been made lower precedence than addition, but it wasn't. And, honestly, having different precedence rules on the same operator depending on the type of the operands is messy.)Newton
U
0

Its all about Method Overloading.

There are individual methods for each data type in println() method

If you pass object :

Prints an Object and then terminate the line. This method calls at first String.valueOf(x) to get the printed object's string value, then behaves as though it invokes print(String) and then println().

If you pass Primitive type:

corresponding primitive type method calls

if you pass String :

corresponding println(String x) method calls

Unprovided answered 15/6, 2013 at 7:49 Comment(0)
R
0

I think you are confused with the printf(String format, Object... args) method. The first argument is the format string, which is mandatory, rest you can pass an arbitrary number of Objects.

There is no such overload for both the print() and println() methods.

Religieux answered 15/6, 2013 at 7:49 Comment(0)
A
0

You can convert anything to a String as long as you choose what to print. The requirement was quite simple since Objet.toString() can return a default dumb string: package.classname + @ + object number.

If your print method should return an XML or JSON serialization, the basic result of toString() wouldn't be acceptable. Even though the method succeed.

Here is a simple example to show that Java can be dumb

public class MockTest{

String field1;

String field2;

public MockTest(String field1,String field2){
this.field1=field1;
this.field2=field2;
}

}

System.out.println(new MockTest("a","b");

will print something package.Mocktest@3254487 ! Even though you only have two String members and this could be implemented to print

Mocktest@3254487{"field1":"a","field2":"b"}

(or pretty much how it appears in the debbuger)

Apace answered 15/6, 2013 at 9:36 Comment(0)
B
0

@ikis, firstly as @Devolus said these are not multiple aruements passed to print(). Indeed all these arguments passed get concatenated to form a single String. So print() does not teakes multiple arguements (a. k. a. var-args). Now the concept that remains to discuss is how print() prints any type of the arguement passed to it.

To explain this - toString() is the secret:

System is a class, with a static field out, of type PrintStream. So you're calling the println(Object x) method of a PrintStream.

It is implemented like this:

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

As wee see, it's calling the String.valueOf(Object) method. This is implemented as follows:

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

And here you see, that toString() is called.

So whatever is returned from the toString() method of that class, same gets printed.

And as we know the toString() is in Object class and thus inherits a default iplementation from Object.

ex: Remember when we have a class whose toString() we override and then we pass that ref variable to print, what do you see printed? - It's what we return from the toString().

Barksdale answered 16/10, 2018 at 7:10 Comment(0)
C
0

The scenarios that you have mentioned are not of overloading, you are just concatenating different variables with a String.

System.out.print("Hello World");

System.out.print("My name is" + foo);

System.out.print("Sum of " + a + "and " + b + "is " + c); 

System.out.print("Total USD is " + usd);

in all of these cases, you are only calling print(String s) because when something is concatenated with a string it gets converted to a String by calling the toString() of that object, and primitives are directly concatenated. However if you want to know of different signatures then yes print() is overloaded for various arguments.

Cyndicyndia answered 16/10, 2018 at 7:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.