一尘不染

Java String类如何覆盖+运算符?

java

当String是类时,为什么在Java中可以使用+运算符添加String?在String.java代码中,我没有找到该操作符的任何实现。这个概念是否违反了面向对象?


阅读 681

收藏
2020-03-03

共1个答案

一尘不染

让我们看一下下面的Java简单表达式

int x=15;
String temp="x = "+x;

编译器"x = "+x;StringBuilder内部进行转换,并用于.append(int)将整数“添加”到字符串中。

5.1.11。字符串转换

可以通过字符串转换将任何类型转换为String类型。

首先将原始类型T的值x转换为参考值,就像通过将其作为适当的类实例创建表达式的参数(第15.9节):

  • 如果T为布尔值,则使用新的Boolean(x)。
  • 如果T为char,则使用新的Character(x)。
  • 如果T为byte,short或int,则使用新的Integer(x)。
  • 如果T长,则使用新的Long(x)。
  • 如果T为float,则使用新的Float(x)。
  • 如果T为double,则使用新的Double(x)。
  • 然后,通过字符串转换将该参考值转换为String类型。

现在只需要考虑参考值:

  • 如果引用为null,则将其转换为字符串“ null”(四个ASCII字符n,u,l,l)。
  • 否则,转换的执行就好像是通过调用不带参数的引用对象的toString方法进行的;但是,如果调用toString方法的结果为null,则使用字符串“ null”。
    toString方法由原始类Object(第4.3.2节)定义。许多类都覆盖它,特别是布尔,字符,整数,长整型,浮点型,双精度和字符串。

有关字符串转换上下文的详细信息,请参见§5.4。

15.18.1。

字符串连接的优化: 实现可以选择一步执行转换和连接,以避免创建然后丢弃中间String对象。为了提高重复字符串连接的性能,Java编译器可以使用StringBuffer类或类似的技术来减少通过对表达式求值创建的中间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习惯用法的简写形式。

2020-03-03