Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

unboxing or toString() is used in sysout in java

Tags:

java

We know that when we use objects in sysout(System.out.Println) statement internally it's toString method is called. and with primitive it directly prints. but when we use any Wrapper class type of objects is used say suppose Integer like following

      Integer i = new Integer(10)
      System.out.Println(i);

is it toString() is responsible for printing it or Unboxing?

like image 849
GuruKulki Avatar asked Jan 23 '10 12:01

GuruKulki


3 Answers

A quick test and debug run shows that print(Object) is invoked, not print(int).

A good way to check this is :

Integer val = null;
System.out.print(val);

If un-boxing were used, this would throw a NullPointerException. This doesn't happen, though, it prints the string null, which is the output of String.valueOf(Object) when a null is passed in.

Another aspect to bear in mind is that PrintStream existed before Java 5. When autoboxing was introduced in Java 5, it had to be ensured that any existing code using PrintStream would not suddenly have its behaviour changed. So any existing code calling print(Object) must not suddenly have its behaviour changed to call print(int) instead, simply because of a new language feature. Backwards compatibility must always be maintained.

like image 63
skaffman Avatar answered Oct 06 '22 04:10

skaffman


(...) but when we use any Wrapper class type of objects is used say suppose Integer like following

  Integer i = new Integer(10)
  System.out.println(i);

is it toString() is responsible for printing it or Unboxing?

You're passing an Object to println so it's obviously println(Object obj) that is called which writes the output of String.valueOf(obj) which calls obj.toString() if obj is not null.

PS: No offense but, why don't you just look at the sources?

Update: I've maybe missed the point of the question (which is misleading in its current form if I may). Actually, the question might be:

(...) but when we use any Wrapper class type of objects is used say suppose Integer like following

  Integer i = new Integer(10)
  System.out.println(i);

What method will be called: println(Object) or println(int)?

If this is what the question is about, then the answer lies of course in The Java Language Specification. To simplify, the method invoked at run time will be the method that is determined at compile-time. Now, how does the compiler determine the method that will be invoked? Well, this is explained in the section 15.12 Method Invocation Expressions. I won't cover all the details, the spec does it better than me but, basically, the first step is to find the class or interface to search, the second step is to find all applicable methods and then to pick up the most specific method, the third step is to verify if the chosen method is appropriate. I'll focus on the 2nd step (which is the interesting one here). As detailed in section 15.12.2 Compile-Time Step 2: Determine Method Signature:

A method is applicable if it is either applicable by subtyping (§15.12.2.2), applicable by method invocation conversion (§15.12.2.3), or it is an applicable variable arity method (§15.12.2.4).

The process of determining applicability begins by determining the potentially applicable methods (§15.12.2.1). The remainder of the process is split into three phases.


Discussion

The purpose of the division into phases is to ensure compatibility with older versions of the Java programming language.


The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.


Discussion

This guarantees that any calls that were valid in older versions of the language are not considered ambiguous as a result of the introduction of variable arity methods, implicit boxing and/or unboxing.


The second phase (§15.12.2.3) performs overload resolution while allowing boxing and unboxing, but still precludes the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the third phase.


Discussion

This ensures that a variable arity method is never invoked if an applicable fixed arity method exists.


The third phase (§15.12.2.4) allows overloading to be combined with variable arity methods, boxing and unboxing.

Deciding whether a method is applicable will, in the case of generic methods (§8.4.4), require that actual type arguments be determined. Actual type arguments may be passed explicitly or implicitly. If they are passed implicitly, they must be inferred (§15.12.2.7) from the types of the argument expressions.

If several applicable methods have been identified during one of the three phases of applicability testing, then the most specific one is chosen, as specified in section §15.12.2.5. See the following subsections for details.

In this particular case, println(Obj) is applicable by subtyping (and println(int) would be applicable by invocation conversion as boxing/unboxing is a conversion (§5.3)). So the compiler will enter the phase 1. And if we look at the last sentence:

If no method applicable by subtyping is found, the search for applicable methods continues with phase 2 (§15.12.2.3). Otherwise, the most specific method (§15.12.2.5) is chosen among the methods that are applicable by subtyping.

Here, there aren't any other methods applicable by subtyping so this is the end, println(Object) will be invoked (and thus toString() will be called, to answer the initial question).

like image 34
Pascal Thivent Avatar answered Oct 06 '22 04:10

Pascal Thivent


All of this predates autoboxing, which was introduced in 1.5. The code that answers these questions -- or the API docs -- hasn't changed at all for 1.5+.

Basically, at the end of the line is the toString method for non-primitives like instances of Integer.

So first, with primitives, there's a different treatment for each one. For int, for instance

Prints an integer. The string produced by String.valueOf(int) is translated into bytes according to the platform's default character encoding, and these bytes are written in exactly the manner of the write(int) method.

But for objects like Integer, println calls print which:

Print an object. The string produced by the String.valueOf(Object) method is translated into bytes according to the platform's default character encoding, and these bytes are written in exactly the manner of the write(int) method.

So what does valueOf use? This is the answer to your question: for Integer its toString method is called. This is from the docs on String.valueOf

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

like image 44
Dan Rosenstark Avatar answered Oct 06 '22 02:10

Dan Rosenstark