I know I can do something like this in Java:
String foo = 'a' + "bee";
If I print foo
to the console I'd get abee
. What is actually happening under the covers here? I assume 'a'
is being promoted to a String
, but I'm not sure what rules govern this type of conversion. It doesn't seem to be a case of autoboxing as far as I can tell, as autoboxing maps from a primitive type to a wrapper class (e.g. int
-> Integer
). Is a String
considered a wrapper for a char
?
One thing that makes this a bit more interesting is that if I do something like
String test = 'a' + 'b';
I get a compilation error. I understand that this is because characters are treated as integers when they're added, though it seems reasonable to expect that I'd get something like "ab"
in test
given the behaviour when adding char
and String
.
You precisely named the reason why using the +
operator for string concatenation can be seen as a historical design mistake. Providing a builtin concatenation operator is not wrong, but it should not have been the plus operator.
Besides the confusion about different behavior, e.g. for 'a'+'b'
and ""+'a'+'b'
, the plus operator is normally expected to be commutative, i.e. a + b
has the same result as b + a
, which doesn’t hold for string concatenation. Further, the operator precedence can lead to surprises.
The behavior is precisely specified (JLS §15.18.1):
15.18.1. String Concatenation Operator +
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.The result of string concatenation is a reference to a
String
object that is the concatenation of the two operand strings. The characters of the left-hand operand precede the characters of the right-hand operand in the newly created string.
This definition links to §5.1.11:
5.1.11. String Conversion
Any type may be converted to type
String
by string conversion.A value
x
of primitive typeT
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
isboolean
, then usenew Boolean(x)
.If
T
ischar
, then usenew Character(x)
.If
T
isbyte
,short
, orint
, then usenew Integer(x)
.If
T
islong
, then usenew Long(x)
.If
T
isfloat
, then usenew Float(x)
.If
T
isdouble
, 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 charactersn
,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 isnull
, then the string "null
" is used instead.
(The spec’s formatting truly is "null
" rather than "null"
)
So the behavior of String foo = 'a' + "bee";
is specified to be as-if you’ve written String foo = new Character('a').toString() + "bee";
But the cited §15.18.1 continues with:
The
String
object is newly created (§12.5) unless the expression is a constant expression (§15.28).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 theStringBuffer
class or a similar technique to reduce the number of intermediateString
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.
So for your specific example, 'a' + "bee"
, the actual behavior of
String foo = 'a' + "bee";
will be
String foo = "abee";
without any additional operations at runtime, because it is a compile-time constant.
If one of the operands is not a compile-time constant, like
char c = 'a';
String foo = c + "bee";
The optimized variant, as used by most if not all compilers from Java 5 to Java 8 (inclusive), is
char c = 'a';
String foo = new StringBuilder().append(c).append("bee").toString();
See also this answer. Starting with Java 9, a different approach will be used.
The resulting behavior will always be like specified.
This is a kind of feature of + operator in JVM.
IF at least one of its operands is String
then the second one will also be converted to String
.
So if you have the following code you will be surprised by the result:
int i = 1;
int j = 1;
System.out.println("Sum of two ints: " + i + j);
This will result to Sum of two ints: 11
since both i
and j
are converted to String and then String concatenation is used.
But if you use the following code then you will get the sum
int i = 1;
int j = 1;
System.out.println("Sum of two ints: " + (i + j));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With