A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 孙浩迪 中级黑马   /  2012-7-24 17:11  /  1365 人查看  /  1 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

出于方便的考虑,我们在进行字符串的内容处理的时候往往会出现以下的代码:
        String result="";
        result+="ok";
这段代码看上去好像没有什么问题,但是需要指出的是其性能很低,原因是java中的String类不可变的(immutable),这段代码实际的工作过程会是如何的呢?通过使用javap工具我们可以知道其实上面的代码在编译成字节码的时候等同的源代码是:
        String result="";
        StringBuffer temp=new StringBuffer();
        temp.append(result);
        temp.append("ok");
        result=temp.toString();
短短的两个语句怎么呢变成这么多呢?问题的原因就在String类的不可变性上,而java程序为了方便简单的字符串使用方式对+操作符进行了重载,而这个重载的处理可能因此误导很多对java中String的使用。
下面给出一个完整的代码:

public class Perf {
  public static String detab1(String s)
  {
    if (s.indexOf('\t') == -1)
      return s;
    String res = "";
    int len = s.length();
    int pos = 0;
    int i = 0;
    for (; i < len && s.charAt(i) == '\t'; i++)  
    {
      res += "        ";
      pos += 8;
    }
    for (; i < len; i++)  
    {
      char c = s.charAt(i);
      if (c == '\t') {
        do {
          res += " ";
          pos++;
        } while (pos % 8 != 0);
      }
      else {
        res += c;
        pos++;
      }
    }
    return res;
  }
      
  public static String detab2(String s)
  {
    if (s.indexOf('\t') == -1)
      return s;
    StringBuffer sb = new StringBuffer();
    int len = s.length();
    int pos = 0;
    int i = 0;
    for (; i < len && s.charAt(i) == '\t'; i++)  
    {
      sb.append("        ");
      pos += 8;
    }
    for (; i < len; i++) {
      char c = s.charAt(i);
      if (c == '\t') {
        do {
          sb.append(' ');
          pos++;
        } while (pos % 8 != 0);
      }
      else {
        sb.append(c);
        pos++;
      }
    }
    return sb.toString();
  }
         
  public static String testlist[] = {
    "",
    "\t",
    "\t\t\tabc",
    "abc\tdef",
    "1234567\t8",
    "12345678\t9",
    "123456789\t"
  };
         
  public static void main(String args[])
  {
    for (int i = 0; i < testlist.length; i++) {
      String tc = testlist[i];
      if (!detab1(tc).equals(detab2(tc)))
        System.err.println(tc);
     }
         
     String test_string =
       "\t\tthis is a test\tof detabbing performance";
     int N = 5000;
     int i = 0;
         
     long ct = System.currentTimeMillis();
     for (i = 1; i <= N; i++)
       detab1(test_string);
     long elapsed = System.currentTimeMillis() - ct;
     System.out.println("String time = " + elapsed);
         
     ct = System.currentTimeMillis();
     for (i = 1; i <= N; i++)
       detab2(test_string);
     elapsed = System.currentTimeMillis() - ct;
     System.out.println("StringBuffer time = "  
       + elapsed);
   }
}
执行以上代码的结果可以看到使用StringBuffer的版本的方法比使用String版本的一般都快十倍以上(本人使用的是JDK1.4.0),你可以执行一下看看结果到底如何。
因此得到的结论是:如果你对字符串中的内容经常进行操作,特别是内容要修改时,那么使用StringBuffer,如果最后需要String,那么使用StringBuffer的toString()方法好了!也许这就是你的程序的性能瓶颈!

评分

参与人数 1技术分 +1 收起 理由
田向向 + 1 赞一个!

查看全部评分

1 个回复

倒序浏览
事实上,String类被设计成为不可改变(immutable)的类。
如果你要改变其值,可以,但JVM在运行时根据新值悄悄创建了一个新对象,然后将这个对象的地址返回给原来类的引用。
这个创建过程虽说是完全自动进行的,但它毕竟占用了更多的时间。
在对时间要求比较敏感的环境中,会带有一定的不良影响。
而StringBuffer类却不是如此,如果你更改了它的实例,但是在Heap Memory的缓冲池中
索引的是同一个实例.
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马