String类如何覆盖+运算符?
为什么在Java中,当String是一个类时,您可以使用+运算符添加string? 在String.java
代码中,我没有find这个操作符的任何实现。 这个概念是否违反了面向对象?
我们来看看Java中的以下简单expression式
int x=15; String temp="x = "+x;
编译器将"x = "+x;
到内部的StringBuilder
并使用.append(int)
将整数“添加”到string中。
5.1.11。 string转换
任何types都可以通过string转换转换为stringtypes。
原始typesT的值x首先转换为参考值,就像将其作为参数提供给适当的类实例创buildexpression式(第15.9节)一样:
- 如果T是布尔值,则使用新的布尔(x)。
- 如果T是char,则使用新的Character(x)。
- 如果T是byte,short或int,则使用新的Integer(x)。
- 如果T很长,则使用新的Long(x)。
- 如果T是浮点数,则使用新的Float(x)。
- 如果T是双倍的,则使用新的Double(x)。
然后通过string转换将该引用值转换为stringtypes。
现在只需要考虑参考值:
- 如果引用为空,则将其转换为string“null”(四个ASCII字符n,u,l,l)。
- 否则,转换就像通过调用不带参数的被引用对象的toString方法一样执行。 但是如果调用toString方法的结果为空,则使用string“null”。
toString方法由原始类Object(§4.3.2)定义。 许多类覆盖它,特别是布尔,Character,Integer,Long,Float,Double和String。
有关string转换上下文的详细信息,请参阅第5.4节。
15.18.1。
string串联的优化:实现可以select一步执行转换和连接,以避免创build并丢弃中间string对象。 为了提高重复string连接的性能,Java编译器可以使用StringBuffer类或类似技术来减less通过评估expression式创build的中间String对象的数量。
对于基本types,实现也可以通过直接从基元types转换为string来优化封装器对象的创build。
优化后的版本实际上并不会实际完成一个完整的包装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();
换句话说,string连接中的运算符+
实际上是更详细的StringBuilder
习惯用法的简写。
它是检查+
运算符的操作数的Java编译器function。 并根据操作数生成字节码:
- 对于string,它会生成连接string的代码
- 对于数字,它会生成添加数字的代码。
这是Java规范所说的 :
运算符+和
-
被称为加法运算符。 AdditiveExpression:MultiplicativeExpression AdditiveExpression + MultiplicativeExpression AdditiveExpression – MultiplicativeExpression加法运算符具有相同的优先级,并且在语法上是左结合的(它们从左到右)。 如果
+
操作符的操作数的types是String
,则操作是string连接。否则,
+
运算符的每个操作数的types必须是可以转换(§5.1.8)为基本数字types的types,否则会发生编译时错误。在任何情况下,二进制运算符的每个操作数的types都必须是可以转换(§5.1.8)为基本数字types的types,否则会发生编译时错误。
String类如何覆盖+运算符?
它不。 编译器做到了。 严格来说,编译器会为String操作数重载 +运算符。
首先(+)超载不超载
Java语言为string连接运算符(+)提供了特殊支持,该运算符已为Javastring对象重载。
-
如果左边的操作数是String,则它作为串联使用。
-
如果左边的操作数是Integer,则它作为加法运算符
Java语言为string连接运算符(+)和其他对象转换为string提供了特殊的支持。 string连接是通过StringBuilder
(或StringBuffer
)类及其append
方法实现的。
应用于String
的+
运算符的含义由语言定义,因为每个人都已经写过。 既然你似乎没有觉得这足够令人信服,考虑这一点:
Ints,float和double都有不同的二进制表示,因此,在位操作方面,添加两个整数是比添加两个浮点数不同的操作:对于整数,您可以逐位添加,携带一个位并检查溢出; 对于浮游物,你必须分别处理曼陀罗和指数。
所以,原则上“加法”取决于“加”对象的性质。 Java定义了它的string,以及整数和浮点数(longs,double …)
+
运算符通常在编译时由StringBuilder
replace。 查看这个答案 ,了解更多关于此事的细节。