String类如何覆盖+运算符?

时间:2012-07-10 07:21:02

标签: java string object

为什么在Java中,当String是类时,你能用+运算符添加字符串?在String.java代码中,我找不到此运算符的任何实现。这个概念是否违反了面向对象?

7 个答案:

答案 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编译器功能,用于检查+运算符的操作数。并根据操作数生成字节码:

  • 对于String,它生成用于连接字符串的代码
  • 对于Numbers,它会生成添加数字的代码。

这是Java规范所说的

  

运算符+和-称为加法运算符。       AdditiveExpression:           MultiplicativeExpression           AdditiveExpression + MultiplicativeExpression           AdditiveExpression - MultiplicativeExpression

     

加法运算符具有相同的优先级并且在语法上       左联想(他们从左到右分组)。 如果是哪种类型       +运算符的操作数为String,则操作为字符串连接。

     

否则,+运算符的每个操作数的类型必须是       是可转换的(第5.1.8节)到原始数字类型,或发生编译时错误。

     

在每种情况下,二进制-运算符的每个操作数的类型必须是       可转换(第5.1.8节)到原始数字类型的类型,或者       发生编译时错误。

答案 2 :(得分:14)

  

String类如何覆盖+运算符?

没有。编译器做到了。严格地说,编译器重载 String操作符的+运算符。

答案 3 :(得分:6)

首先(+)重载而不是重写

  

Java语言为字符串提供特殊支持   连接运算符(+),已为Java字符串重载   对象。

  1. 如果左侧操作数是String,则它作为连接。

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

答案 4 :(得分:4)

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

答案 5 :(得分:4)

+运算符在应用于String时的含义由语言定义,正如每个人已经编写的那样。既然你似乎没有找到足够的说服力,请考虑一下:

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

因此,原则上,“添加”取决于被“添加”的对象的性质。 Java为字符串以及整数和浮点数(longs,double,......)定义它

答案 6 :(得分:3)

+运算符通常在编译时被StringBuilder替换。有关此问题的详细信息,请查看此answer