How is an int
value automatically converted into a String
when we concatenate a String
with an int
? For example, consider this code:
int i=5;
String s="A"+i;
The output is "A5". So, how was i
converted into a String
before it was concatenated with "A"
?
This is defined in the JLS. Section 15.18.1 (string concatenation operator) has:
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.
Section 5.1.11 has:
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 (§15.9):
If T is
boolean
, then usenew Boolean(x)
.If T is
char
, then usenew Character(x)
.If T is
byte
,short
, orint
, then usenew Integer(x)
.If T is
long
, then usenew Long(x)
.If T is
float
, then usenew Float(x)
.If T is
double
, then usenew 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 thetoString
method is null, then the string"null"
is used instead.
Now that's the general process. In the code in your title (String s = "A" + 5
), this is a constant expression (section 15.28), so the compiler performs the concatenation at compile time, ensuring the result is the same as it would have been by following the above steps at execution time. That doesn't happen for the code in the body of your question, where you're using a variable for the int
.
In fact, the description above only explains what the result of string concatenation should be - the compiler can (and does, in the case of the Oracle JDK) use the overloads of StringBuilder.append
to perform the relevant conversions - it trusts that the result will be the same as performing the conversion using the above step and then appending.
To demonstrate that, compile a class containing this method:
public void concatenation() {
// Declare the variable x separately so that the concatenation expression
// is not a constant expression. (*We* know the result, but the language
// rules don't classify it as a constant expression.)
int x = 5;
String y = "A" + x;
}
Then decompile it with javap -c
and you'll see:
public void concatenation();
Code:
0: iconst_5
1: istore_1
2: new #3; // class java/lang/StringBuilder
5: dup
6: invokespecial #4; // Method java/lang/StringBuilder."<init>":()V
9: ldc #5; // String A
11: invokevirtual #6; // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: iload_1
15: invokevirtual #7; // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
18: invokevirtual #8; // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
21: astore_2
22: return
In other words, the method is equivalent to:
public void concatenation() {
int x = 5;
StringBuilder tmp = new StringBuilder();
tmp.append("A");
tmp.append(x);
String y = tmp.toString();
}
The exact details of the use of StringBuilder
are a compiler implementation detail, however. For example, it could pass "A"
into the StringBuilder
constructor, or provide an expected size to the StringBuilder
.
See more on this question at Stackoverflow