全面解释java中StringBuilder、StringBuffer、String类之间的关系
2015-09-30 10:32
218 查看
String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且大量浪费有限的内存空间,StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象,StringBuffer和StringBuilder类功能基本相似
1. String 类
String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且大量浪费有限的内存空间。
String a = "a"; //假设a指向地址0x0001
a = "b";//重新赋值后a指向地址0x0002,但0x0001地址中保存的"a"依旧存在,但已经不再是a所指向的,a 已经指向了其它地址。
因此String的操作都是改变赋值地址而不是改变值操作。
2. StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。 每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量。
StringBuffer buf=new StringBuffer(); //分配长16字节的字符缓冲区
StringBuffer buf=new StringBuffer(512); //分配长512字节的字符缓冲区
StringBuffer buf=new StringBuffer("this is a test")//在缓冲区中存放了字符串,并在后面预留了16字节的空缓冲区。
3.StringBuffer
StringBuffer和StringBuilder类功能基本相似,主要区别在于StringBuffer类的方法是多线程、安全的,而StringBuilder不是线程安全的,相比而言,StringBuilder类会略微快一点。对于经常要改变值的字符串应该使用StringBuffer和StringBuilder类。
4.线程安全
StringBuffer 线程安全
StringBuilder 线程不安全
5.速度
一般情况下,速度从快到慢:StringBuilder<StringBuffer<String,这种比较是相对的,不是绝对的。
6 其实StringBuffer和StringBuilder都是继承的
疑问:
为什么要(旧值+1)*2呢?
我自己的想法:
也许是考虑到value.length的值可能为0(初始化时设置StringBuffer的capactity为0).
或者考虑到溢出的情况?
但是可能是JVM的某些限制,我的机器数组最大可以设置为30931306,再大就报错:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
30931306这个数字好奇怪
还有哪方面的考虑么?谁知道,能告诉我么?
参考http://blog.sina.com.cn/s/blog_7de5c6210100t641.html
http://www.jb51.net/article/33398.htm
6.总结
(1).如果要操作少量的数据用 = String
(2).单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
(3).多线程操作字符串缓冲区 下操作大量数据 = StringBuffer
复制代码 代码如下:
运行结果:
操作java.lang.String类型使用的时间为:4105毫秒
操作java.lang.StringBuffer类型使用的时间为:2毫秒
操作java.lang.StringBuilder类型使用的时间为:1毫秒
操作字符串对象引用相加类型使用的时间为:8毫秒
操作字符串相加使用的时间为:0毫秒
1. String 类
String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且大量浪费有限的内存空间。
String a = "a"; //假设a指向地址0x0001
a = "b";//重新赋值后a指向地址0x0002,但0x0001地址中保存的"a"依旧存在,但已经不再是a所指向的,a 已经指向了其它地址。
因此String的操作都是改变赋值地址而不是改变值操作。
2. StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。 每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量。
StringBuffer buf=new StringBuffer(); //分配长16字节的字符缓冲区
StringBuffer buf=new StringBuffer(512); //分配长512字节的字符缓冲区
StringBuffer buf=new StringBuffer("this is a test")//在缓冲区中存放了字符串,并在后面预留了16字节的空缓冲区。
3.StringBuffer
StringBuffer和StringBuilder类功能基本相似,主要区别在于StringBuffer类的方法是多线程、安全的,而StringBuilder不是线程安全的,相比而言,StringBuilder类会略微快一点。对于经常要改变值的字符串应该使用StringBuffer和StringBuilder类。
4.线程安全
StringBuffer 线程安全
StringBuilder 线程不安全
5.速度
一般情况下,速度从快到慢:StringBuilder<StringBuffer<String,这种比较是相对的,不是绝对的。
6 其实StringBuffer和StringBuilder都是继承的
AbstractStringBuilder implements java.io.Serializable, CharSequence 实现的原理是利用数组来存储字符, /** * The value is used for character storage. */ char[] value; /** * The count is the number of characters used. */ int count; 每次插入之前先保证内存足够 public void ensureCapacity(int minimumCapacity) { if (minimumCapacity > 0) ensureCapacityInternal(minimumCapacity); } /** * This method has the same contract as ensureCapacity, but is * never synchronized. */ private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code if (minimumCapacity - value.length > 0) expandCapacity(minimumCapacity); } /** * This implements the expansion semantics of ensureCapacity with no * size check or synchronization. */ void expandCapacity(int minimumCapacity) { int newCapacity = value.length * 2 + 2; //两倍增长+2 if (newCapacity - minimumCapacity < 0) newCapacity = minimumCapacity; if (newCapacity < 0) { if (minimumCapacity < 0) // overflow throw new OutOfMemoryError(); newCapacity = Integer.MAX_VALUE; } value = Arrays.copyOf(value, newCapacity); }
疑问:
为什么要(旧值+1)*2呢?
我自己的想法:
也许是考虑到value.length的值可能为0(初始化时设置StringBuffer的capactity为0).
或者考虑到溢出的情况?
但是可能是JVM的某些限制,我的机器数组最大可以设置为30931306,再大就报错:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
30931306这个数字好奇怪
还有哪方面的考虑么?谁知道,能告诉我么?
参考http://blog.sina.com.cn/s/blog_7de5c6210100t641.html
http://www.jb51.net/article/33398.htm
6.总结
(1).如果要操作少量的数据用 = String
(2).单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
(3).多线程操作字符串缓冲区 下操作大量数据 = StringBuffer
所以在单线程环境下StringBuilder的性能要好于StringBuffer, 使用字符串常量的相加,而不要使用字符串对象String相加,String对象相加是比较耗时的操作。
以下是代码与演示说明:复制代码 代码如下:
public class TestString { private final static int COUNT = 50000; // 循环次数 public TestString() { } public void test(String s) { long begin = System.currentTimeMillis(); for (int i = 0; i < COUNT; ++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 < COUNT; ++i) s.append("add"); long over = System.currentTimeMillis(); System.out.println("操作" + s.getClass().getCanonicalName() + "类型使用的时间为:" + (over - begin) + "毫秒"); } public void test(StringBuilder s) { long begin = System.currentTimeMillis(); for (int i = 0; i < COUNT; ++i) s.append("add"); long over = System.currentTimeMillis(); System.out.println("操作" + s.getClass().getName() + "类型使用的时间为:" + (over - begin) + "毫秒"); } /* 对 String 直接进行字符串拼接的测试 */ public void test2() { long begin = System.currentTimeMillis(); String s2 = "abcd"; String s = null; for (int i = 0; i < COUNT; ++i) { s = s2 + s2 + s2; } long over = System.currentTimeMillis(); System.out.println("操作字符串对象引用相加类型使用的时间为:" + (over - begin) + "毫秒"); } public void test3() { long begin = System.currentTimeMillis(); String s = null; for (int i = 0; i < COUNT; ++i) { s = "abcd" + "abcd" + "abcd"; } long over = System.currentTimeMillis(); System.out.println("操作字符串相加使用的时间为:" + (over - begin) + "毫秒"); } public static void main(String[] args) { String s1 = "abcd"; StringBuffer st1 = new StringBuffer("abcd"); StringBuilder st2 = new StringBuilder("abcd"); TestString tc = new TestString(); tc.test(s1); tc.test(st1); tc.test(st2); tc.test2(); tc.test3(); } }
运行结果:
操作java.lang.String类型使用的时间为:4105毫秒
操作java.lang.StringBuffer类型使用的时间为:2毫秒
操作java.lang.StringBuilder类型使用的时间为:1毫秒
操作字符串对象引用相加类型使用的时间为:8毫秒
操作字符串相加使用的时间为:0毫秒
相关文章推荐
- zoj 3820 Building Fire Stations(二分法+bfs)
- UILabel详解
- iOS学习笔记——UIPickerView的简单应用
- 【十三】注入框架RoboGuice采用:(Logging via Ln)
- UIImageView显示图片的相关设置
- iphone 屏幕适配(各个机型上UItabbleview显示行数一样多、字体等比放大,4和4s除外)
- UITextView详解
- Android GUI之View事件处理(二)
- SoapUI管理Cookie
- Android UI系列-----Dialog对话框
- 铜梁视窗代码生成器C#,自动生成Model,BaseDAL,包含所有Insert,Update,Delete和QueryList方法
- HDU5493 Queue(线段树)
- UILabel的相关属性设置
- UITextField和UITextView被键盘遮住的处理办法
- iOS 使用xib创建UITableViewCell的时候引用另外一个UITableViewCell时报错
- No suitable authentication method found to complete authentication.
- iOS 注册或登录页面(UILable,UITextField,UIButton)
- iOS开发UI_UIRefreshControl
- UI_属性传值
- UISwich控件的相关属性