4

I just want to know one simple thing in Java. Let's consider the following segment of code In Java.

int x=10;
String temp="x = "+x;
System.out.println(temp);

is perfectly valid in Java and produces the output, x = 10 as a string.


Although, the variable x is of type int, it is automatically converted to a String type (a wrapper type). How does Java do this? Does operator overloading somewhat or somewhere exist in Java like the one above as with C++ and C#?, though it was removed from Java. Which specific concept is used here to convert x into a string. The only thing I want to know


and also, one more question, in Java a boolean data type (not Boolean, a wrapper class), can not be converted to any other type (as per I'm knowing). Why is it so, in some very specific situations , it may useful to convert it to a string or some other types.

Bhavesh
  • 4,607
  • 13
  • 43
  • 70
  • Please ask one question only. – Tim Nov 03 '11 at 23:30
  • 2
    To answer your side question, the only thing it is truly useful to have a boolean in another form for would be outputting to the user or some other human readable form, and it converts to "true" or "false" when appending to a string or with a StringBuilder. Anything else, it should be handled individually by the developer, not cast. – corsiKa Nov 03 '11 at 23:35
  • Although it would be nice for JDBC drivers to convert Booleans into PL/SQL numeric 0 and 1s so I don't have to write a bunch of lousy helper procedures. ;-) – Scott A Nov 03 '11 at 23:37
  • @ScottAnderson - you seriously expect JDBC to cater for broken extension languages that can't do their own type conversions? – Stephen C Nov 04 '11 at 00:05
  • Adding to @glowcoder's comment, the fact that Java has no automatic conversions between boolean and int is a **good thing** because it virtually eliminates the `if (i = 1) ...` bug syndrome. IIRC, this was a conscious design decision. – Stephen C Nov 04 '11 at 00:09
  • No, absolutely not, but while I'm feeling lazy it would be nice... ;-). – Scott A Nov 04 '11 at 00:10

3 Answers3

9

The compiler converts that phrase ("x = "+x) into a StringBuilder internally and uses .append(int) to "add" the integer to the string.

To go beyond the practical "how does Java do this", I'll take the advice of Stephen and give the theoretical as well. Conceptually, each value in the concatenation is first converted to a String and then concatenated. Nulls are concatenated as the word "null".

From the Java Language Specification:

15.18.1.1 String Conversion

Any type may be converted to type String by string conversion. A value x of primitive type T is first converted to a reference value as if by giving it as an argument to an appropriate class instance creation expression:

If T is boolean, then use new Boolean(x). If T is char, then use new Character(x). If T is byte, short, or int, then use new Integer(x). If T is long, then use new Long(x). If T is float, then use new Float(x). If T is double, then use new Double(x). This reference value is then converted to type String by string conversion. 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.

The toString method is defined by the primordial class Object; many classes override it, notably Boolean, Character, Integer, Long, Float, Double, and String.

15.18.1.2 Optimization of String Concatenation

An implementation may choose to perform conversion and concatenation in one step to avoid creating and then discarding an intermediate String object. To increase the performance of repeated string concatenation, a Java compiler may use the StringBuffer class or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression. For primitive types, an implementation may also optimize away the creation of a wrapper object by converting directly from a primitive type to a string.

The optimized version will not actually do a full wrapped String conversion first.

This is a good illustration of an optimized version used by the compiler, albeit without the conversion of a primitive, where you can see the compiler changing things into a StringBuilder in the background:

http://caprazzi.net/posts/java-bytecode-string-concatenation-and-stringbuilder/

This java code:

public static void main(String[] args) {
    String cip = "cip";
    String ciop = "ciop";
    String plus = cip + ciop;
    String build = new StringBuilder(cip).append(ciop).toString();
}

Generates this - see how the two concatenation styles lead to the very same bytecode:

 L0
    LINENUMBER 23 L0
    LDC "cip"
    ASTORE 1
   L1
    LINENUMBER 24 L1
    LDC "ciop"
    ASTORE 2
// cip + ciop
   L2
    LINENUMBER 25 L2

    NEW java/lang/StringBuilder
    DUP
    ALOAD 1
    INVOKESTATIC java/lang/String.valueOf(Ljava/lang/Object;)Ljava/lang/String;
    INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
    ALOAD 2
    INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;

    ASTORE 3
    // new StringBuilder(cip).append(ciop).toString()
   L3
    LINENUMBER 26 L3

    NEW java/lang/StringBuilder
    DUP
    ALOAD 1
    INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
    ALOAD 2
    INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;

    ASTORE 4
   L4
    LINENUMBER 27 L4
    RETURN

The compiler has transformed "cip+ciop" into "new StringBuilder(cip).append(ciop).toString()". In other words, "+" is effectively a shorthand for the more verbose StringBuilder idiom.

Scott A
  • 7,745
  • 3
  • 33
  • 46
  • 2
    And it will also accept any types for the right operand for + operators on strings. For class instances it will use the Object.toString() method, if not overridden by one of inheriting child classes. With base types it will do something similar. Object.toString(), if not overridden and the output for array instances will not be very usefull. Using e.g. 1 + "" will not work, since an integer instance will not allow a StringBuilder to be created, trying to do integer addition instea ("" + 1 is fine as workaround). – Maarten Bodewes Nov 03 '11 at 23:36
  • 1
    I should point out that reading bytecodes is the lazy way to answer these questions. If you tried this approach with (say) C or C++, you'd end up with all sorts of incorrect ideas ... and fragile programs that broke when you changed compiler switches, etc. The correct way to gain an understanding of Java is to read the JLS or a good text book ... not the bytecodes. – Stephen C Nov 04 '11 at 00:26
  • 1
    I knew to look for a byte code example because I have actually read the JLS, thankyouverymuch. ;-) Sometimes a practical example gets the point across in a more immediate fashion, and the OP did specifically ask how it was done. – Scott A Nov 04 '11 at 01:59
1

Java does support limited operator overloading ... for built-in operators with certain combinations of (primitive) operand types. The main cases are:

  • The arithmetic operators have overloads for different numeric primitive types. The '+' operator is additionally overloaded for string concatenation.

  • The '&', '|', '^' and '!' operators are overloaded for (non-short-circuit) logical and bitwise integral operations.

However, Java does not support any form of programmer-defined operators or operator overloading.


Answers that say overloading is "compiler magic" or that "the compiler does it" are missing the point. The Java language specification says that it is part of the language, what it means, and (pretty much) mandates how it should be implemented.


As another answer points out, auto-boxing / unboxing and other things are (strictly speaking) conversions and not overloading. So for example:

int j = ...
Integer i = ...
j = j + i;

This uses the (int, int) overload of the '+' operator, and uses auto-unboxing to convert the 2nd operand to an int.

byte b = ...
j = j + b;

This uses the (int, int) overload of the '+' operator, and uses an cast to convert the 2nd operand to an int.

Note that the JLS specifies the rules that determine which operator overload is used based on the (initial) types of the operands. So, in the 2nd example, the JLS mandates that the (int, int) overload of '+' is used, not the (byte, byte) overload.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • I didn't say the compiler was doing operator overloading. I said it was internally converting the phrase into StringBuilder.append() calls. Not the same thing at all. – Scott A Nov 03 '11 at 23:49
  • @ScottAnderson - but you are still missing the real point. The OP needs to know that this is not just some clever compiler stuff. It is JLS stuff, and he should be referring to the JLS (or a good Java text book) to really understand what is going on here. [ Reading bytecodes is for lazy people who can't be bothered to read the JLS ;-) ] – Stephen C Nov 04 '11 at 00:21
  • Point taken, see above, but many (most?) people learn best from a practical example, not theory. Conceptually the JLS says one thing happens, but then goes on to say, "well, actually you can do it like this for the sake of optimization". – Scott A Nov 04 '11 at 02:00
0

It's all compiler magic. You can't do operator overloading in Java.

crosses fingers and hopes this isn't horribly wrong and gets me 20 downvotes

G_H
  • 11,739
  • 3
  • 38
  • 82
  • It's not wrong, but it will get you downvotes for not being sure none-the-less. – Maarten Bodewes Nov 03 '11 at 23:40
  • @owlstead I'm just having a bit of a laugh. Pretty sure of what I said here, but I'm not so cocky as to think that even my most strongly held beliefs can't be based on rickety foundations. – G_H Nov 03 '11 at 23:43
  • 2
    Votes should never be based on someones confidence in their answer; instead they should be based solely on the usefulness of an answer. In my opinion, if someone is mostly confident in their answer but are still unsure, I want to know! That's more useful to me. That being said, whenever you're unsure, you have to ask yourself what you would need to do to make yourself completely sure. In this case, it would be consulting the JLS. Which if you want to be MOST useful you would want to do before posting, or perhaps immediately after. – corsiKa Nov 04 '11 at 01:00