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对象重载。

  1. 如果左边的操作数是String,则它作为串联使用。

  2. 如果左边的操作数是Integer,则它作为加法运算符

Java语言为string连接运算符(+)和其他对象转换为string提供了特殊的支持。 string连接是通过StringBuilder (或StringBuffer )类及其append方法实现的。

应用于String+运算符的含义由语言定义,因为每个人都已经写过。 既然你似乎没有觉得这足够令人信服,考虑这一点:

Ints,float和double都有不同的二进制表示,因此,在位操作方面,添加两个整数是比添加两个浮点数不同的操作:对于整数,您可以逐位添加,携带一个位并检查溢出; 对于浮游物,你必须分别处理曼陀罗和指数。

所以,原则上“加法”取决于“加”对象的性质。 Java定义了它的string,以及整数和浮点数(longs,double …)

+运算符通常在编译时由StringBuilderreplace。 查看这个答案 ,了解更多关于此事的细节。