`

Java中的StringBuilder类功能详解

阅读更多
Java中的StringBuilder类功能详解

字符串连接可以通过两种方法实现,其中一种是在Java中提供的一个StringBuilder类(这个类只在J2SE5及以上版本提供,以前的版本使用StringBuffer类)。
字符串是Java程序中最常用的一种数据结构之一。在Java中的String类已经重载的"+"。也就是说,字符串可以直接使用"+"进行连接,如下面代码所示:

String s = "abc" + "ddd"; 但这样做真的好吗?当然,这个问题不能简单地回答yes or no。要根据具体情况来定。在Java中提供了一个StringBuilder类(这个类只在J2SE5及以上版本提供,以前的版本使用StringBuffer类),这个类也可以起到"+"的作用。那么我们应该用哪个呢?

下面让我们先看看如下的代码:

package string;
        public class TestSimplePlus    {
        public static void main(String[] args)        {
            String s = "abc";
            String ss = "ok" + s + "xyz" + 5;
            System.out.println(ss);        }
    } 

上面的代码将会输出正确的结果。从表面上看,对字符串和整型使用"+"号并没有什么区别,但事实真的如此吗?下面让我们来看看这段代码的本质。

我们首先使用反编译工具(如jdk带的javap、或jad)将TestSimplePlus反编译成Java Byte Code,其中的奥秘就一目了然了。在本文将使用jad来反编译,命令如下:

jad -o -a -s d.java TestSimplePlus.class


反编译后的代码如下:

package string;
   import java.io.PrintStream;
   public class TestSimplePlus  {
      public TestSimplePlus()      {
      //   0  0:aload_0         
      //   1  1:invokespecial   #8   < Method void Object()>      
      //    2    4:return          
      }   
    public static void main(String args[])      {
        String s = "abc";
      //    0    0:ldc1            #16  < String "abc">   
      //    1    2:astore_1       
        String ss = (new StringBuilder("ok")).append(s).append("xyz").append(5).toString();
      //    2    3:new             #18  < Class StringBuilder>
      //    3    6:dup             
      //    4    7:ldc1            #20  < String "ok"> 
      //    5    9:invokespecial   #22  < Method void StringBuilder(String)> 
      //    6   12:aload_1      
      //    7   13:invokevirtual   #25  < Method StringBuilder StringBuilder.append(String)>
      //    8   16:ldc1            #29  < String "xyz">
      //    9   18:invokevirtual   #25  < Method StringBuilder StringBuilder.append(String)> 
      //   10   21:iconst_5      
      //   11   22:invokevirtual   #31  < Method StringBuilder StringBuilder.append(int)>
      //   12   25:invokevirtual   #34  < Method String StringBuilder.toString()>
      //   13   28:astore_2
        System.out.println(ss);
      //   14   29:getstatic       #38  < Field PrintStream System.out>
      //   15   32:aload_2       
      //   16   33:invokevirtual   #44  < Method void PrintStream.println(String)>
      //   17   36:return           
     }  
}  

读者可能看到上面的Java字节码感到迷糊,不过大家不必担心。本文的目的并不是讲解Java Byte Code,因此,并不用了解具体的字节码的含义。

使用jad反编译的好处之一就是可以同时生成字节码和源代码。这样可以进行对照研究。从上面的代码很容易看出,虽然在源程序中使用了"+",但在编译时仍然将"+"转换成StringBuilder。因此,我们可以得出结论,在Java中无论使用何种方式进行字符串连接,实际上都使用的是StringBuilder类。

那么是不是可以根据这个结论推出使用"+"和StringBuilder类的效果是一样的呢?这个要从两个方面的解释。如果从运行结果来解释,那么"+"和StringBuilder是完全等效的。但如果从运行效率和资源消耗方面看,那它们将存在很大的区别。

当然,如果连接字符串行表达式很简单(如上面的顺序结构),那么"+"和StringBuilder类基本是一样的,但如果结构比较复杂,如使用循环来连接字符串,那么产生的Java Byte Code就会有很大的区别。先让我们看看如下的代码:

package string;
      import java.util.*;
      public class TestComplexPlus   { 
      public static void main(String[] args)       {
           String s = "";
           Random rand = new Random();
           for (int i = 0; i <  10; i++)           {
               s = s + rand.nextInt(1000) + " ";
           }
           System.out.println(s); 
      }
   } 

上面的代码返编译后的Java Byte Code如下:

package string;
   import java.io.PrintStream;
  import java.util.Random;
   public class TestComplexPlus  {
       public TestComplexPlus()      {
      //    0    0:aload_0       
      //    1    1:invokespecial   #8   < Method void Object()>     //    2    4:return            
    } 
    public static void main(String args[])      {
          String s = "";
      //    0    0:ldc1            #16  < String "">
      //    1    2:astore_1
          Random rand = new Random();
      //    2    3:new             #18  < Class Random>
      //    3    6:dup             
      //    4    7:invokespecial   #20  < Method void Random()>
      //    5   10:astore_2        
          for(int i = 0; i <  10; i++)
      //*   6   11:iconst_0       
      //*   7   12:istore_3        
      //*   8   13:goto            49
           s = (new StringBuilder(String.valueOf(s))).append(rand.nextInt(1000)).append(" ").toString();
      //    9   16:new             #21  < Class StringBuilder>
      //   10   19:dup             
      //   11   20:aload_1          
      //   12   21:invokestatic    #23  < Method String String.valueOf(Object)>
      //   13   24:invokespecial   #29  < Method void StringBuilder(String)>
      //   14   27:aload_2       
      //   15   28:sipush          1000
      //   16   31:invokevirtual   #32  < Method int Random.nextInt(int)> 
      //   17   34:invokevirtual   #36  < Method StringBuilder StringBuilder.append(int)>
      //   18   37:ldc1            #40  < String " ">
      //   19   39:invokevirtual   #42  < Method StringBuilder StringBuilder.append(String)>
      //   20   42:invokevirtual   #45  < Method String StringBuilder.toString()>
      //   21   45:astore_1        
      //   22   46:iinc            3  1
      //   23   49:iload_3        
      //   24   50:bipush          10
      //   25   52:icmplt          16
          System.out.println(s); 
      //   26   55:getstatic       #49  < Field PrintStream System.out> 
      //   27   58:aload_1         
      //   28   59:invokevirtual   #55  < Method void PrintStream.println(String)>
      //   29   62:return            
    }  
} 

大家可以看到,虽然编译器将"+"转换成了StringBuilder类,但创建StringBuilder对象的位置却在for语句内部。这就意味着每执行一次循环,就会创建一个StringBuilder对象(对于本例来说,是创建了10个StringBuilder对象),虽然Java有垃圾回收器,但这个回收器的工作时间是不定的。如果不断产生这样的垃圾,那么仍然会占用大量的资源。解决这个问题的方法就是在程序中直接使用StringBuilder类来连接字符串,代码如下:

package string;
   import java.util.*;
   public class TestStringBuilder  {
      public static void main(String[] args)      {
          String s = "";
          Random rand = new Random();
          StringBuilder result = new StringBuilder();
          for (int i = 0; i <  10; i++)          {
              result.append(rand.nextInt(1000));
              result.append(" ");
          }
          System.out.println(result.toString());
      }
  }

 上面代码反编译后的结果如下:

package string;
   import java.io.PrintStream;
  import java.util.Random;
   public class TestStringBuilder  {
       public TestStringBuilder()      {
      //    0    0:aload_0        
       //    1    1:invokespecial   #8   < Method void Object()>      //    2    4:return         
       }
       public static void main(String args[])      {
          String s = "";
      //    0    0:ldc1            #16  < String "">
      //    1    2:astore_1
                  Random rand = new Random();
      //    2    3:new             #18  < Class Random>
      //    3    6:dup           
      //    4    7:invokespecial   #20  < Method void Random()>
      //    5   10:astore_2
                  StringBuilder result = new StringBuilder();
      //    6   11:new             #21  < Class StringBuilder>
      //    7   14:dup              
      //    8   15:invokespecial   #23  < Method void StringBuilder()>
      //    9   18:astore_3
                  for(int i = 0; i <  10; i++)
      //*  10   19:iconst_0        
      //*  11   20:istore          4
      //*  12   22:goto            47          {              result.append(rand.nextInt(1000));
      //   13   25:aload_3       
      //   14   26:aload_2      
      //   15   27:sipush          1000
      //   16   30:invokevirtual   #24  < Method int Random.nextInt(int)>
      //   17   33:invokevirtual   #28  < Method StringBuilder StringBuilder.append(int)>
      //   18   36:pop
                           result.append(" ");
      //   19   37:aload_3       
      //   20   38:ldc1            #32  < String " ">
      //   21   40:invokevirtual   #34  < Method StringBuilder StringBuilder.append(String)>
      //   22   43:pop
                       }
      //   23   44:iinc            4  1
      //   24   47:iload           4
      //   25   49:bipush          10
      //   26   51:icmplt          25
          System.out.println(result.toString());
      //   27   54:getstatic       #37  < Field PrintStream System.out>
      //   28   57:aload_3
     //   29   58:invokevirtual   #43  < Method String StringBuilder.toString()>
      //   30   61:invokevirtual   #47  < Method void PrintStream.println(String)>
      //   31   64:return
                }
  }
 
从上面的反编译结果可以看出,创建StringBuilder的代码被放在了for语句外。虽然这样处理在源程序中看起来复杂,但却换来了更高的效率,同时消耗的资源也更少了。

在使用StringBuilder类时要注意,尽量不要"+"和StringBuilder混着用,否则会创建更多的StringBuilder对象,如下面代码所:

for (int i = 0; i <  10; i++)  {
      result.append(rand.nextInt(1000));
      result.append(" ");  }

 改成如下形式:

for (int i = 0; i <  10; i++)  {
       result.append(rand.nextInt(1000) + " ");
  }

则反编译后的结果如下:

 for(int i = 0; i <  10; i++)
  //*  10   19:iconst_0    
  //*  11   20:istore          4
  //*  12   22:goto            65
   {
    result.append((new StringBuilder(String.valueOf(rand.nextInt(1000)))).append(" ").toString());
  //   13   25:aload_3 
  //   14   26:new             #21  < Class StringBuilder>
  //   15   29:dup  
           
从上面的代码可以看出,Java编译器将"+"编译成了StringBuilder类,这样for语句每循环一次,又创建了一个StringBuilder对象。

如果将上面的代码在JDK1.4下编译,必须将StringBuilder改为StringBuffer,而JDK1.4将"+"转换为StringBuffer(因为JDK1.4并没有提供StringBuilder类)。StringBuffer和StringBuilder的功能基本一样,只是StringBuffer是线程安全的,而StringBuilder不是线程安全的。因此,StringBuilder的效率会更高。

分享到:
评论

相关推荐

    java中stringBuilder的用法详解

    Java 中的 StringBuilder 用法详解 Java 中的 StringBuilder 是一个可变的字符串对象,主要用于字符串的操作和修改。下面将详细介绍 StringBuilder 的用法和常用方法。 StringBuilder 的创建 可以使用重载的构造...

    java StringBuilder详解

    在Java编程语言中,`StringBuilder`类是字符串操作的一个重要工具,尤其在处理大量字符串拼接时,它的效率远高于`String`类。本篇文章将深入解析`StringBuilder`的使用方法、内部机制以及与`StringBuffer`的区别。 ...

    java StringBuilder类的详解及简单实例

    Java StringBuilder类详解及简单实例 Java StringBuilder类是Java语言中的一种字符串操作类,它提供了多种字符串操作方法,如追加、插入、替换、删除等。下面将详细介绍Java StringBuilder类的详解及简单实例。 一...

    详解C++中StringBuilder类的实现及其性能优化

    在Java和C#中,StringBuilder可以创造可变字符序列来动态地扩充字符串,那么在C++中我们同样也可以实现一个StringBuilder并且用来提升性能,下面就来详解C++中StringBuilder类的实现及其性能优化

    StringBuffer 和 StringBuilder 类

    《Java中的StringBuffer与StringBuilder类详解》 在Java编程中,当我们需要对字符串进行多次修改时,StringBuffer和StringBuilder类成为首选。这两个类提供了一种高效且灵活的方式来处理字符串,与不可变的String类...

    Java类库 java中常用的类 可以参考

    - **主要功能**:提供了访问和处理来自于 Java 标准数据源数据的类。 - **关键类**: - `Connection`:与数据库的连接。 - `Statement`:执行 SQL 语句。 - `ResultSet`:存储查询结果。 ##### 11. `java.util.*...

    JavaSE之StringBuilder类与String类

    #### 二、StringBuilder类详解 **2.1 StringBuilder简介** `StringBuilder`是Java提供的一个可变字符串类,它可以更高效地处理字符串的拼接操作。相比于`String`,`StringBuilder`在进行多次字符串拼接时,能显著...

    Java 中String StringBuilder 与 StringBuffer详解及用法实例

    在Java编程语言中,String、StringBuilder和StringBuffer都是用来处理字符串的重要类,它们各有特点,适用于不同的场景。这里我们将深入探讨这三个类的区别、特性和使用策略。 首先,String类是不可变的,这意味着...

    java CharSequence、String、StringBuffer、StringBuilder详解

    在Java编程语言中,`CharSequence`是一个接口,它是字符序列的抽象基类,包括`String`、`StringBuffer`和`StringBuilder`等类。理解这些类的特点和用途是优化程序性能的关键。以下是对这些概念的详细解释: 1. `...

    Java中String、StringBuffer、StringBuilder的区别详解

    Java中的字符串处理是编程中常见的任务,涉及到三个关键类:String、StringBuffer和StringBuilder。它们在功能上相似,但有着重要的区别,主要体现在字符串的可变性、线程安全性和性能方面。 1. 可变性 - String类...

    07 StringBuilder

    ### Java中的StringBuilder详解 在Java编程语言中,`StringBuilder`是一个非常重要的类,它提供了一种高效地构建和操作字符串的方式。与`String`不同,`StringBuilder`对象是可变的,这意味着可以在不创建新对象的...

    Java中String类的详细文档打印版

    ### Java中String类详解 #### 引言 在Java编程语言中,`String`类扮演着至关重要的角色,它用于表示字符序列。本文档旨在深入探讨`String`类的特性和功能,帮助开发者更好地理解和应用这一核心类。 #### String类...

    java String、StringBuilder和StringBuffer的区别详解

    Java中的`String`、`StringBuilder`和`StringBuffer`都是用来处理字符串的类,它们各自有不同的特性和适用场景。在理解它们之间的区别之前,我们首先要知道它们的共同点。 **共同点:** 1. **都是字符串类**:这三...

    Java软件开发实战 Java基础与案例开发详解 9-2 StringBuffer和String Builder类共9页.pdf

    ### Java软件开发实战:StringBuffer和StringBuilder类 #### 1. 概述 在Java编程中,处理字符串是一项常见的需求。对于需要频繁修改的字符串,使用`String`类可能会导致性能问题,因为每次修改都会创建一个新的`...

    基于StringBuilder类中的重要方法(介绍)

    StringBuilder类中的重要方法详解 StringBuilder类是Java中一个非常重要的类,用于字符串的操作和处理。下面我们将对StringBuilder类中的重要方法进行详解。 append方法 append方法用于将参数的字符串表示形式...

    Java软件开发实战 Java基础与案例开发详解 9-1 常用类介绍 共15页.pdf

    ### Java软件开发实战:Java基础与案例开发详解 #### 第9章:常用类介绍 **学前提示** ...接下来,我们将继续深入探讨其他常用的Java类,如`StringBuilder`、`Date`等,进一步扩展我们的Java技能树。

    java基础案例与开发详解案例源码全

    9.3 StringBuilder类的使用233 9.4 日期类简介234 9.5 Java语言国际化时间获取与计算238 9.6 Random类和Math类240 9.7 本章习题243 第10章 10.1 异常概述246 10.2 使用try和catch捕获异常..2 50 10.3 使用throw和...

    JAVA常用8种类的使用方法详解

    `StringBuffer`类用于操作可变的字符串,与`StringBuilder`类似,但在多线程环境中更安全。它提供了追加、插入、删除、反转字符串等功能。 #### Random类 `Random`类用于生成随机数。它提供了生成整数、浮点数和...

    Java实现和维护系统详解.pdf

    在Java编程中,性能优化是至关重要的,尤其是在大型系统中,每一行代码的效率都可能影响到整体的系统性能。描述中提到的日志代码优化是一个典型的例子,它使用了条件语句来避免不必要的日志输出,减少计算开销。`if ...

    java小型记事本 值得借鉴

    3. 文件I/O操作:为了实现文件的打开、保存功能,我们需要使用Java的File类和FileInputStream/OutputStream等流类进行文件读写操作。 4. 文本处理:对于文本编辑器,理解String和StringBuilder类,以及它们在处理...

Global site tag (gtag.js) - Google Analytics