为什么在Java中,当String是类时,你能用+运算符添加字符串?在String.java
代码中,我找不到此运算符的任何实现。这个概念是否违反了面向对象?
答案 0 :(得分:154)
让我们看看Java中的以下简单表达式
int x=15;
String temp="x = "+x;
编译器在内部将"x = "+x;
转换为StringBuilder
,并使用.append(int)
将整数“添加”到字符串中。
<强> 5.1.11. String Conversion 强>
任何类型都可以通过字符串转换转换为String类型。
首先将基元类型T的值x转换为参考值 好像通过将它作为参数提供给适当的类实例 创作表达式(§15.9):
- 如果T是布尔值,则使用new Boolean(x)。
- 如果T为char,则使用new Character(x)。
- 如果T是byte,short或int,则使用new Integer(x)。
- 如果T很长,则使用新的Long(x)。
- 如果T为float,则使用new Float(x)。
- 如果T为double,则使用new Double(x)。
然后,此参考值将按字符串转换为String类型 转换。
现在只需要考虑参考值:
- 如果引用为null,则将其转换为字符串“null”(四个ASCII字符n,u,l,l)。
- 否则,转换的执行就好像通过调用没有参数的引用对象的toString方法一样;但 如果调用toString方法的结果为null,那么 改为使用字符串“null”。
toString方法由原始类Object定义 (§4.3.2)。许多类都覆盖它,特别是布尔,字符, 整数,长整数,浮点数,双精度和字符串。
有关字符串转换上下文的详细信息,请参见§5.5。
<强> 15.18.1. 强>
字符串连接的优化: 实现可以选择执行转换和连接 在一步中避免创建然后丢弃中间体 字符串对象。增加重复字符串的性能 连接,Java编译器可以使用StringBuffer类或a 类似的技术减少了中间String对象的数量 通过评估表达式创建的。
对于原始类型,实现也可以优化掉 通过直接从基元转换来创建包装器对象 键入字符串。
优化版本实际上不会首先执行完全包装的String转换。
这是编译器使用的优化版本的一个很好的例证,虽然没有原语的转换,你可以看到编译器在后台将事物更改为StringBuilder:
http://caprazzi.net/posts/java-bytecode-string-concatenation-and-stringbuilder/
这个java代码:
public static void main(String[] args) {
String cip = "cip";
String ciop = "ciop";
String plus = cip + ciop;
String build = new StringBuilder(cip).append(ciop).toString();
}
生成这个 - 看两个连接样式如何导致相同的字节码:
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
查看上面的示例以及如何生成基于给定示例中的源代码的字节代码,您将能够注意到编译器已在内部转换了以下语句
cip+ciop;
进入
new StringBuilder(cip).append(ciop).toString();
换句话说,字符串连接中的运算符+
实际上是更详细的StringBuilder
习语的简写。
答案 1 :(得分:27)
它是Java编译器功能,用于检查+
运算符的操作数。并根据操作数生成字节码:
这是Java规范所说的:
运算符+和
-
称为加法运算符。 AdditiveExpression: MultiplicativeExpression AdditiveExpression + MultiplicativeExpression AdditiveExpression - MultiplicativeExpression加法运算符具有相同的优先级并且在语法上 左联想(他们从左到右分组)。 如果是哪种类型
+
运算符的操作数为String
,则操作为字符串连接。否则,
+
运算符的每个操作数的类型必须是 是可转换的(第5.1.8节)到原始数字类型,或发生编译时错误。在每种情况下,二进制
-
运算符的每个操作数的类型必须是 可转换(第5.1.8节)到原始数字类型的类型,或者 发生编译时错误。
答案 2 :(得分:14)
String类如何覆盖+运算符?
没有。编译器做到了。严格地说,编译器重载 String操作符的+运算符。
答案 3 :(得分:6)
首先(+)重载而不是重写
Java语言为字符串提供特殊支持 连接运算符(+),已为Java字符串重载 对象。
如果左侧操作数是String,则它作为连接。
如果左侧操作数为Integer,则它作为加法运算符
答案 4 :(得分:4)
Java语言为字符串连接运算符(+)以及将其他对象转换为字符串提供特殊支持。字符串连接是通过StringBuilder
(或StringBuffer
)类及其append
方法实现的。
答案 5 :(得分:4)
+
运算符在应用于String
时的含义由语言定义,正如每个人已经编写的那样。既然你似乎没有找到足够的说服力,请考虑一下:
Ints,float和double都有不同的二进制表示,因此在位操作方面添加两个int是一个不同的操作,而不是添加两个浮点数:对于int,你可以逐位添加,携带一个位并检查溢出;对于花车,你必须分别处理尾数和指数。
因此,原则上,“添加”取决于被“添加”的对象的性质。 Java为字符串以及整数和浮点数(longs,double,......)定义它
答案 6 :(得分:3)
+
运算符通常在编译时被StringBuilder
替换。有关此问题的详细信息,请查看此answer。