java - 当我在 Java 中添加一个字符和一个字符串时会发生什么?

标签 java string char

我知道我可以在 Java 中做这样的事情:
String foo = 'a' + "bee";
如果我打印 foo到控制台我会得到 abee .这里的幕后究竟发生了什么?我假设 'a'正在晋升为String ,但我不确定什么规则管理这种类型的转换。据我所知,这似乎不是自动装箱的情况,因为自动装箱从原始类型映射到包装类(例如 int -> Integer)。是String被认为是 char 的包装器?

让这更有趣的一件事是,如果我做类似的事情
String test = 'a' + 'b';我收到编译错误。我知道这是因为字符在添加时被视为整数,尽管期望我得到类似 "ab" 的东西似乎是合理的。在 test给定添加 char 时的行为和 String .

最佳答案

您准确说出了使用 + 的原因用于字符串连接的运算符可以被视为历史设计错误。提供内置连接运算符并没有错,但它不应该是加号运算符。
除了对不同行为的混淆,例如为 'a'+'b'""+'a'+'b' ,加号运算符通常是可交换的,即 a + bb + a 的结果相同,这不适用于字符串连接。此外,运算符优先级可能会导致意外。
行为是 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.


此定义链接到 §5.1.11 :

5.1.11. 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 (§15.9):

  • 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.


(规范的格式确实是“null ”而不是 "null" )
所以String foo = 'a' + "bee";的行为被指定为就像你写了 String foo = new Character('a').toString() + "bee";但是引用的 §15.18.1 continues和:

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 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.


所以对于你的具体例子,'a' + "bee" , 实际行为
String foo = 'a' + "bee";
将会
String foo = "abee";
在运行时没有任何额外的操作,因为它是一个编译时常量。
如果操作数之一不是编译时常量,例如
char c = 'a';
String foo = c + "bee";
从 Java 5 到 Java 8(包括在内)的大多数编译器(如果不是全部)使用的优化变体是
char c = 'a';
String foo = new StringBuilder().append(c).append("bee").toString();
另见 this answer .从 Java 9 开始,a different approach将会被使用。
结果行为将始终与指定的一样。

关于java - 当我在 Java 中添加一个字符和一个字符串时会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60011556/

相关文章:

c++ - g++/gcc 中 char 的符号及其历史

java - 将字符串中的每个单词或数字组合加倍

c - C 中字符比较的段错误

java - 低于 24 的 android api 级别不支持

java - 每次发短信都是 'show permission dialog '怎么解决?

Python按索引从字符串中删除字符的最佳方法

c# 将 console.writeline 转换为字符串

python - 有没有办法让 vim 自动换行 79 个字符的 python 字符串?

java - 从 Clojure 调用可变参数 Java 函数时出现问题

Java vector 线程安全