文档章节

深入理解 String, StringBuffer 与 StringBuilder 的区别

大数据之路
 大数据之路
发布于 2013/01/16 02:35
字数 3049
阅读 1451
收藏 7
点赞 0
评论 0

String 字符串常量
StringBuffer字符串变量(线程安全)
StringBuilder字符串变量(非线程安全)

 简要的说, String 类型和StringBuffer类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。
 而如果是使用StringBuffer类则结果就不一样了,每次结果都会对StringBuffer对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用StringBuffer,特别是字符串对象经常改变的情况下。而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了StringBuffer对象的拼接,所以这些时候 String 对象的速度并不会比StringBuffer对象慢,而特别是以下的字符串对象生成中, String 效率是远要比StringBuffer快的:
 String S1 = “This is only a” + “ simple” + “ test”;
 StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
 你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候StringBuffer居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个
 String S1 = “This is only a” + “ simple” + “test”; 其实就是:
 String S1 = “This is only a simple test”; 所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象的话,速度就没那么快了,譬如:
String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;
这时候 JVM 会规规矩矩的按照原来的方式去做


在大部分情况下StringBuffer > String
StringBuffer

Java.lang.StringBuffer线程安全的可变字符序列。一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。

每个字符串缓冲区都有一定的容量。只要字符串缓冲区所包含的字符序列的长度没有超出此容量,就无需分配新的内部缓冲区数组。如果内部缓冲区溢出,则此容量自动增大。从 JDK 5.0 开始,为该类增添了一个单个线程使用的等价类,即 StringBuilder 。与该类相比,通常应该优先使用 StringBuilder 类,因为它支持所有相同的操作,但由于它不执行同步,所以速度更快。

可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。
StringBuffer上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。
例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append("le") 会使字符串缓冲区包含“startle”,而 z.insert(4, "le") 将更改字符串缓冲区,使之包含“starlet”。
在大部分情况下StringBuilder StringBuffer

java.lang.StringBuilder

java.lang.StringBuilder一个可变的字符序列是5.0新增的。此类提供一个与StringBuffer兼容的 API,但不保证同步。类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer要快。两者的方法基本相同。

但是如果将 StringBuilder 的实例用于多个线程是不安全的。需要这样的同步,则建议使用 StringBuffer 。

ok,Talk is cheap,show you the code:

package com.test;

public class Testssb {
	   
    /** Creates a new instance of testssb */
    final static int ttime = 70000;// 测试循环次数
    public Testssb() {
    }
   
    public void test(String s){
        long begin = System.currentTimeMillis();
        for(int i=0;i<ttime;i++){
            s += "add";
        }
        long over = System.currentTimeMillis();
        System.out.println(" 操作 "+s.getClass().getName()+" 类型使用的时间为: "
            + (over - begin) + " 毫秒 " );       
    }
    public void test(StringBuffer s){
        long begin = System.currentTimeMillis();
        for(int i=0;i<ttime;i++){
            s.append("add");
        }
        long over = System.currentTimeMillis();
        System.out.println(" 操作 "+s.getClass().getName()+" 类型使用的时间为: "
            + (over - begin) + " 毫秒 " );       
    }
    public void test(StringBuilder s){
        long begin = System.currentTimeMillis();
        for(int i=0;i<ttime;i++){
            s.append("add");
        }
        long over = System.currentTimeMillis();
        System.out.println(" 操作 "+s.getClass().getName()+" 类型使用的时间为: "
            + (over - begin) + " 毫秒 " );       
    }
    // 对 String 直接进行字符串拼接的测试
    public void test2(){
        String s2 = "abadf";
        long begin = System.currentTimeMillis();
        for(int i=0;i<ttime;i++){
            String s = s2 + s2 + s2 ;
        }
        long over = System.currentTimeMillis();
        System.out.println(" 操作字符串对象引用相加类型使用的时间为: "
            + (over - begin) + " 毫秒 " );       
    }
    public void test3(){
        long begin = System.currentTimeMillis();
        for(int i=0;i<ttime;i++){
            String s = "abadf" + "abadf" + "abadf" ;
        }
        long over = System.currentTimeMillis();
        System.out.println(" 操作字符串相加使用的时间为: "
            + (over - begin) + " 毫秒 " );       
    }
   
    public static void main(String[] args){
    String s1 ="abc";
    StringBuffer sb1 = new StringBuffer("abc");
    StringBuilder sb2 = new StringBuilder("abc");
    Testssb t = new Testssb();
    t.test(s1);
    t.test(sb1);
    t.test(sb2);
    t.test2();
    t.test3();
    }
}

测试结果:

 50000
 
 操作 java.lang.String 类型使用的时间为: 10456 毫秒 
 操作 java.lang.StringBuffer 类型使用的时间为: 4 毫秒 
 操作 java.lang.StringBuilder 类型使用的时间为: 3 毫秒 
 操作字符串对象引用相加类型使用的时间为: 23 毫秒 
 操作字符串相加使用的时间为: 1 毫秒 
 
 60000
 操作 java.lang.String 类型使用的时间为: 17455 毫秒 
 操作 java.lang.StringBuffer 类型使用的时间为: 4 毫秒 
 操作 java.lang.StringBuilder 类型使用的时间为: 3 毫秒 
 操作字符串对象引用相加类型使用的时间为: 13 毫秒 
 操作字符串相加使用的时间为: 1 毫秒 

 70000
 操作 java.lang.String 类型使用的时间为: 25882 毫秒 
 操作 java.lang.StringBuffer 类型使用的时间为: 5 毫秒 
 操作 java.lang.StringBuilder 类型使用的时间为: 3 毫秒 
 操作字符串对象引用相加类型使用的时间为: 14 毫秒 
 操作字符串相加使用的时间为: 1 毫秒

你还可以往下继续加大测试数据,只是我的本子扛不住了。。。就不测了。。。

其实我这里测试并不是很公平,因为都放在了一起以先后顺序进行,测试方法中间没有考虑到JVM的GC收集前面产生的无引用对象垃圾而对执行过程的中断时间。如果大家有更好的想法或者思路欢迎跟我讨论:decli AT qq DOT com

关于上文所述:在 JVM 眼里,这个 

String S1 = “This is only a” + “ simple” + “test”; 其实就是: 

String S1 = “This is only a simple test”; 
这里的表述不恰当 
String S1 = “This is only a” + “ simple” + “test”; 其实就是: 

String S1 = “This is only a simple test”; 这么说是对的,但是如果是jvm的把戏,那么String S1 = “This is only a” + “ simple” + “test”; 是不是会和 
String S3=“This is only a”; 
S3+=“ simple”; 
S3+=“test”; 
System.out.println(S1==S3);的结果是一样呢?很显然结果是false; 

其实这并不是JVM的把戏,而是java编译器的把戏。 
给出如下源代码 

package com.test;

public class T {
	
	public static void main(String[] args) {
		String s1 = "This is only a" + " simple " + "test"; 
		String s2 = "This is only a"; 
		s2+= " simple "; 
		s2+= "test"; 
		System.out.println(s1==s2); 
	}
}

那么它编译(JDK5.0)后的class会是什么样的呢:

H:\tmp_download>jad -p T.class
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name:   T.java

package com.test;

import java.io.PrintStream;

public class T
{

    public T()
    {
    }

    public static void main(String args[])
    {
        String s1 = "This is only a simple test";
        String s2 = "This is only a";
        s2 = (new StringBuilder(String.valueOf(s2))).append(" simple ").toString();
        s2 = (new StringBuilder(String.valueOf(s2))).append("test").toString();
        System.out.println(s1 == s2);
    }
}

H:\tmp_download>

可以看到 + 变成了 StringBuilder 的方式,这是Javac的问题,也是Javac优化class的一个技巧。  

http://stackoverflow.com/questions/8725739/stringbuilder-usage

注:不要用 Java decompiler 去编译,这个工具会做一些美化,而要用 JAD:

JAVA高级:反编译工具jad的简单用法

http://tech.sina.com.cn/s/2007-09-28/09061768599.shtml

http://www.varaneckas.com/jad/

最后,我们再来看个常见的问题:

new String() vs literal string(字面量

Java运行环境有一个字符串常量池(String constant pool),由String类维护。执行语句String s="abc"时,首先查看字符串池中是否存在字符串"abc",如果存在则直接将"abc"赋给s,如果不存在则先在字符串池中新建一个字符串"abc",然后再将其赋给s。
执行语句String s=new String("abc")时,在运行时涉及 2 个String实例,一个是字符串字面量"xyz"所对应的、驻留(intern)在一个全局共享的字符串常量池中的实例,另一个是通过new String(String)创建并初始化的、内容与"xyz"相同的实例。
前一语句的效率高,后一语句的效率低,因为新建字符串需要占用内存空间和时间。

注意以下区别:

Also, a little test you can do to drive the point home:

String a = new String("xpto");
String b = new String("xpto");
String c = "xpto";
String d = "xpto";
String e = a.intern();

System.out.println(a == b);
System.out.println(a == c);
System.out.println(c == d);
System.out.println(c == e);
With all this, you can probably figure out the results of these Sysouts:

false
false
true
true
Since c and d are the same object, the == comparison holds true.

intern()

对于上面使用new创建的字符串对象,如果想将这个对象的引用加入到字符串常量池,可以使用intern方法。

调用intern后,首先检查字符串常量池中是否有该对象的引用,如果存在,则将这个引用返回给变量,否则将引用加入并返回给变量。

http://stackoverflow.com/questions/14757978/new-string-vs-literal-string-performance

http://rednaxelafx.iteye.com/blog/774673

http://zhidao.baidu.com/question/26614057.html

http://developer.51cto.com/art/201106/266454.htm  Java中的String与常量池

http://www.iteye.com/topic/634530  Java堆.栈和常量池 笔记

http://droidyue.com/blog/2014/12/21/string-literal-pool-in-java/?comefrom=http://blogread.cn/news/  Java中的字符串常量池

REF:

是 String , StringBuffer 还是 StringBuilder ?

http://www.blogjava.net/chenpengyi/archive/2006/05/04/44492.html

http://baike.baidu.com/view/3645996.htm

深入理解Java中的String

http://g21121.iteye.com/blog/1873262

为什么String类是不可变的? 

http://www.importnew.com/7440.html

JDK6 和 JDK7 中的 substring() 实现差异(JDK6和JDK7中的substring()方法)

http://www.importnew.com/7418.html

Java中的String对象是不可变的吗 

http://www.importnew.com/9468.html

Oracle优化Java字符串内部表示

http://www.infoq.com/cn/news/2013/12/Oracle-Tunes-Java-String

如何写一个不可变类? 

http://www.importnew.com/7535.html

深入理解Java中的final关键字 

http://www.importnew.com/7553.html

Java 性能优化之 String 篇

http://www.ibm.com/developerworks/cn/java/j-lo-optmizestring/

Integer.valueOf(String) 方法之惑 

http://www.importnew.com/9162.html

public static void main(String[] args) throws IOException {
		System.out.println(Integer.valueOf(127)==Integer.valueOf(127));
		System.out.println(Integer.valueOf("127")==Integer.valueOf("127"));
		System.out.println(Integer.valueOf("128")==Integer.valueOf("128"));
		System.out.println(Integer.parseInt("128")==Integer.valueOf("128"));
	}

//
true
false
false
true

Java中关于String类型的10个问题 

http://www.importnew.com/12845.html

什么是字符串常量池? 

http://www.importnew.com/10756.html

Java程序员们最常犯的10个错误 

http://www.importnew.com/12074.html

Java编程提高性能时需注意的地方

http://blog.jobbole.com/16474/

尽量使用基本数据类型代替对象:
String str = "hello";
上面这种方式会创建一个“hello”字符串,而且JVM的字符缓存池还会缓存这个字符串;
String str = new String("hello");
此时程序除创建字符串外,str所引用的String对象底层还包含一个char[]数组,这个char[]数组依次存放了h,e,l,l,o

Java中的substring真的会引起内存泄露么?

http://droidyue.com/blog/2014/12/14/substring-memory-issue-in-java/

浅谈StringBuilder

“for循环中使用 "+" 拼接为什么这么慢”:用 "+" 进行拼接,都会转化成 StringBuilder 对象,但是在for循环中,每循环一次,就创建一个StringBuilder 对象,如果循环1千万次,就创建了1千万个StringBuilder 对象,性能会差很多。

http://www.jianshu.com/p/160c9be0b132

本文转载自:http://space.itpub.net/26308209/viewspace-719801

共有 人打赏支持
大数据之路
粉丝 1485
博文 516
码字总数 344497
作品 0
武汉
架构师
Java深究之String、StringBuffer、StringBuilder的区别

在Java学习中,String、StringBuffer、StringBuilder三者是很重要的,在编写代码中经常使用到他们,那么深入的了解他们的异同是非常重要的,接下里我们详细剖析下这三个的异同之处 首先总结下...

MaxBill
07/02
0
0
think in java 第十三章字符串 总结随笔

String、StringBuffer和StringBuilder的区别 可变与不可变: String对象具有只读的特性,是不可变的,修改一个String的值其实是创建了一个新的String对象。 StringBuffer和StringBuilder都是...

The_flying_pig
2017/08/16
0
0
java中String、StringBuffer、StringBuilder的区别

java中String、StringBuffer、StringBuilder是编程中经常使用的字符串类,他们之间的区别也是经常在面试中会问到的问题。现在总结一下,看看他们的不同与相同。 1.可变与不可变   String类...

ForingY
2016/02/29
26
0
java基础---浅谈Java中的String、StringBuilder以及StringBuffer

浅谈Java中的String、StringBuilder以及StringBuffer 一.你了解String类吗? 想要了解一个类,最好的办法就是看这个类的实现源代码,String类的实现在 jdkxxxxxxsrcjavalangString.java 文件...

android-key
2016/12/11
11
0
探秘Java中String、StringBuilder以及StringBuffer

相信String这个类是Java中使用得最频繁的类之一,并且又是各大公司面试喜欢问到的地方,今天就来和大家一起学习一下String、StringBuilder和StringBuffer这几个类,分析它们的异同点以及了解...

刘星石
2016/03/01
2
0
Java中String、StringBuilder以及StringBuffer区别和关系

相信String这个类是Java中使用得最频繁的类之一,并且又是各大公司面试喜欢问到的地方,今天就来和大家一起学习一下String、StringBuilder和StringBuffer这几个类,分析它们的异同点以及了解...

袁梓皓
2016/03/08
34
0
java中String、StringBuffer、StringBuilder的区别 - jihite

java中String、StringBuffer、StringBuilder的区别 - jihite 博客园jihite2018-01-011 阅读 StringBufferjavaString Java里面提供了String,StringBuffer和StringBuilder三个类来封装字符串 ......

博客园_jihite
01/01
0
0
String,StringBuilder,StringBuffer对比

简述 StringBuilder 对比 StringBuffer StringBuilder是非线程安全 StringBuffer是线程安全的。 StringBuilder和StringBuffer其余的特性都是一样的,他们与String的区别: StringBuilder与S...

Real_man
03/20
0
0
【翻译】Java中String, StringBuffer, StringBuilder的区别

String 是 Java 中最重要的类之一,并且任何刚开始做Java编程的人,都会用String定义一些内容,然后通过著名的System.out.println()语句来打印出来。 然而,很多Java新手都不会意识到 String...

YuanyuanL
2014/09/03
0
4
String、StringBuilder、StringBuffer

相信大家看到过很多比较String和StringBuffer区别的文章,也明白这两者的区别,然而自从Java 5.0发布以后,我们的比较列表上将多出一个对象了,这就是StringBuilder类。String类是不可变类,...

Elivense
2016/12/19
5
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

win10 上安装解压版mysql

1.效果 2. 下载MySQL 压缩版 下载地址: https://downloads.mysql.com/archives/community/ 3. 配置 3.1 将下载的文件解压到合适的位置 我最终将myql文件 放在:D:\develop\mysql 最终放的位...

Lucky_Me
10分钟前
0
0
linux服务器修改mtu值优化cpu

一、jumbo frames 相关 1、什么是jumbo frames Jumbo frames 是指比标准Ethernet Frames长的frame,即比1518/1522 bit大的frames,Jumbo frame的大小是每个设备厂商规定的,不属于IEEE标准;...

问题终结者
24分钟前
0
0
expect脚本同步文件expect脚本指定host和要同步的文件 构建文件分发系统批量远程执行命令

expect脚本同步文件 在一台机器上把文件同步到多台机器上 自动同步文件 #!/usr/bin/expectset passwd "123456"spawn rsync -av root@192.168.133.132:/tmp/12.txt /tmp/expect {"yes...

lyy549745
25分钟前
0
0
36.rsync下 日志 screen

10.32/10.33 rsync通过服务同步 10.34 linux系统日志 10.35 screen工具 10.32/10.33 rsync通过服务同步: rsync还可以通过服务的方式同步。那需要开启一个服务,他的架构是cs架构,客户端服务...

王鑫linux
33分钟前
0
0
matplotlib 保存图片时的参数

简单绘图 import matplotlib.pyplot as pltplt.plot(range(10)) 保存为csv格式,放大后依然很清晰 plt.savefig('t1.svg') 普通保存放大后会有点模糊文件大小20多k plt.savefig('t5.p...

阿豪boy
37分钟前
0
0
java 8 复合Lambda 表达式

comparator 比较器复合 //排序Comparator.comparing(Apple::getWeight);List<Apple> list = Stream.of(new Apple(1, "a"), new Apple(2, "b"), new Apple(3, "c")) .collect(......

Canaan_
昨天
0
0
nginx负载均衡

一、nginx 负载均衡 拓扑图: 主机信息: 1、负载均衡器1(lb1):192.168.10.205 RHEL7.5 2、负载均衡器2(lb2):192.168.10.206 RHEL7.5 3、web服务器1(web01):192.168.10.207 Centos...

人在艹木中
昨天
0
0
做了一个小网站

做了一个小网站 www.kanxs123.com

叶落花开
昨天
0
0
继社会佩奇之后,又尝试了可爱的蓝胖子,有趣 Python

#哆啦A梦# !/usr/bin/env python3# -*- coding: utf-8 -*-# @Author: dong dong# @Env: python 3.6from turtle import *# 无轨迹跳跃def my_goto(x, y): penup(...

Py爱好
昨天
0
0
shell及python脚本方式登录服务器

一、问题 在工作过程中,经常会遇见需要登录服务器,并且因为安全的原因,需要使用交互的方式登录,而且shell、python在工作中也经常用到,并且可以提供交互的功能。都是利用了expect、spawn...

yangjianzhou
昨天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部