String和StringBuilder和StringBuffer三兄弟
来源:互联网 发布:python 面部表情识别 编辑:程序博客网 时间:2024/05/17 04:36
String和StringBuilder和StringBuffer三兄弟
前言
好久之前在写文件上传的时候使用了这样的一段代码
/*** @param rootUrlStr:保存的路径的文件夹路径 假设就是 D:\save* @param fileUriStr:需要保存的文件的具体路径* @about 这是一段精简的代码* @return 存储文件地址*/public String uploadUri1(String rootUrlStr,String fileUriStr) { //下面我将故意使用很复杂的拼接 //获得文件名,故意不使用UUID.randomUUID() String fileNameStr=fileUriStr.substring(fileUriStr.lastIndexOf("\\")); String fileRealUriStr=rootUrlStr+"\\"; fileRealUriStr+="uploadFile\\"; fileRealUriStr+=fileNameStr;//把根路径和文件名拼接在一起 return fileRealUriStr;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
这种写法很明显的一点就是会生成很多的中间对象。
于是我后来改成了这样
public String uploadUri2(String rootUrlStr,String fileUriStr) { //下面我将故意使用很复杂的拼接 //获得文件名,故意不使用UUID.randomUUID() StringBuffer fileRealUriStr=new StringBuffer(rootUrlStr); String fileNameStr=fileUriStr.substring(fileUriStr.lastIndexOf("\\")); fileRealUriStr.append("uploadFile\\").append(fileNameStr); return fileRealUriStr.toString();}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
使用StringBuffer去避免生成太多临时字符串。
当然有更好的方法,那就是使用Paths
public String uploadUri3(String rootUrlStr,String fileUriStr) { //下面使用Path //获得文件名,故意不使用UUID.randomUUID() String fileNameStr=fileUriStr.substring(fileUriStr.lastIndexOf("\\")); Path path=Paths.get(rootUrlStr,"uploadFile",fileNameStr); return path.toString();}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
Paths会自动补全”\”,使得代码比较直观好看。他不是今天的主角,所以我就不展开讲了。
//测试代码public static void main(String[] args) { String string1=new MyText().uploadUri1("D:save","I:\\JAVA\\java.txt"); String string2=new MyText().uploadUri2("D:save","I:\\JAVA\\java.txt"); String string3=new MyText().uploadUri3("D:save","I:\\JAVA\\java.txt"); System.out.println(string1); System.out.println(string2); System.out.println(string3);}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
输出结果
D:save\uploadFile\Java.txt
D:save\uploadFile\java.txt
D:save\uploadFile\java.txt
以上是可以跳过不看的内容
分析
内部实现
String:
String类使用字符串数组保存字符串,因为使用final修饰符,所以可知道String对象是不可变的。所谓的不可变其实是指每次修改都不是在原字符上修改,而是新建了一个新的字符数组,而且如果这个对象没有被引用,那这个对象就是没有用的。
StringBuffer:
继承了AbstractStringBuilder,而且和String不一样的是
String使用的是数组声明为 private final char value[];
StringBuffer的声明是 private transient char[] toStringCache;
transient :临时的
当StringBuffer进行修改时,(比如说删除、更新字符)是在原来的实例对象进行修改的。但是如果是拼接操作时,分成两种情况,1、空间足够,直接拼接;2、空间不够,新建了一个字符串数组,再搬家过去。StringBuilder:
StringBuffer和StringBuffer都是继承了AbstractStringBuilder,区别只是方法签名上是否有synchronized。因此,StringBuffer是线程安全的,而StringBuilder是线程不安全的。
HashTable是线程安全的,很多方法都是synchronized方法,而HashMap不是线程安全的,但其在单线程程序中的性能比HashTable要高。StringBuffer和StringBuilder类的区别也是如此,他们的原理和操作基本相同,区别在于StringBufferd支持并发操作,线性安全的,适 合多线程中使用。StringBuilder不支持并发操作,线性不安全的,不适合多线程中使用。新引入的StringBuilder类不是线程安全的,但其在单线程中的性能比StringBuffer高。
运行速度(StringBuilder>StringBuffer>String)
- String 每次都要新增临时字符串,开销大,很慢(GC工作压力大)
- StringBuffer 建立线程安全容器,开销大,中等
- StringBuilder 单线程推荐使用,线程不安全,快
感觉直接这样说,你还是不相信,还是觉得使用String多好啊,敲起来还短,所以我就提供了一段代码,这段代码不是我原创的,但是写的很好,我就借来修改了一下,代码如下
package javaTest;/** *@author CHEN *@time 2016年4月15日 *@about 测试String StringBuffer StringBuilder的性能 */public class StringBuilderTester { private static final String base = " base string. "; private static final int count = 200000; public static void stringTest() { long begin, end; begin = System.currentTimeMillis(); String test = new String(base); for (int i = 0; i < count ; i++) { test = test + " add "; } end = System.currentTimeMillis(); System.out.println((end - begin) + " millis has elapsed when used String. "); } public static void stringBufferTest() { long begin, end; begin = System.currentTimeMillis(); StringBuffer test = new StringBuffer(base); for (int i = 0; i < count; i++) { test = test.append(" add "); } end = System.currentTimeMillis(); System.out.println((end - begin) + " millis has elapsed when used StringBuffer. "); } public static void stringBuilderTest() { long begin, end; begin = System.currentTimeMillis(); StringBuilder test = new StringBuilder(base); for (int i = 0; i < count; i++) { test = test.append(" add "); } end = System.currentTimeMillis(); System.out.println((end - begin) + " millis has elapsed when used StringBuilder. "); } public static void main(String[] args) { stringTest(); stringBufferTest(); stringBuilderTest(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
运行结果:
113730 millis has elapsed when used String.
13 millis has elapsed when used StringBuffer.
9 millis has elapsed when used StringBuilder.
建议在使用的时候,把count的值乘以10,但stringTest中count缩小100倍,有利于比较StringBuffer和StringBuilder。
线程安全
- String :String是不可变的,所以也就是线程安全的
- StringBuffer:线程安全,
- StringBuilder:线程不安全
package hello;/** * @about 对StringBuffer StringBuilder String的线程测试 * @author CHEN * @time 2016年4月15日 */public class Test { public static void main(String[] args) { StringBuffer sbf = new StringBuffer(); StringBuilder sb = new StringBuilder(); String s=new String(); //10个线程 for (int i = 0; i < 10; i++) { new Thread(new TestThread(sbf, sb, s)).start(); } }}class TestThread implements Runnable { StringBuffer sbf; StringBuilder sb; String s; TestThread(StringBuffer sbf, StringBuilder sb,String s) { this.sb = sb; this.sbf = sbf; this.s=s; } @Override public void run() { for (int i = 0; i < 100; i++) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } sb.append("1"); sbf.append("1"); s+="1"; System.out.println(sb.length() + "/" + sbf.length()+"/"+s.length()); } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
运行的结果是:
sb很少次能达到1000次
sbf基本都达到1000次
而s 则是100次
后言
- 如果阅读String的“+”的字节码,其实你就会发现,在底层,系统自动调用了StringBilder。
例如下面的代码
public class Buffer { public static void main(String[] args) { String s1 = "aaaaa"; String s2 = "bbbbb"; String r = null; int i = 3694; r = s1 + i + s2; for(int j=0;i<10;j++){ r+="23124"; } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
JVM将会翻译成
偷偷的调用了StringBuilder,为什么呢?当然是因为快啊。但是别以为JVM帮你做了这部分工作,你就可以滥用String了。String转成StringBuilder每次都会建立很多的对象的,所以呢,作为一个好的码农,第一件事就是为JVM多考虑。
总结
就这样我们认识了String、StringBuffer、StringBuilder三兄弟。
大哥String,虽说顽固不变,但是通用性好,用途广泛,占用内存小,大众都喜欢使用它。可是呢,其实大哥String的工作经常是交给小弟StringBuilder做的。
二哥StringBuffer,比大哥通达,改变的时候就会改变。可是,别人让他办事,他每次就答应办一件,每次一件,所以比较可靠安全。
小弟StringBuilder,比较活泼,有时候同时办好几件事,就把事给办坏了。可是呢,小弟他的工作效率是最快的。
- 上一篇小小图片爬虫
- 下一篇写一篇漂亮的CSDN-markdown
- String和StringBuilder和StringBuffer三兄弟
- String和StringBuilder和StringBuffer三兄弟
- 不认识String、StringBuffer和StringBuilder这三兄弟的同学赶紧进来
- String、StringBuilder和StringBuffer三者区别
- String 、StringBuffer 和 StringBuilder
- String、StringBuffer和StringBuilder
- String、StringBuffer和StringBuilder
- String、StringBuffer和StringBuilder
- String、StringBuffer和StringBuilder
- String Stringbuffer和StringBuilder
- String ,StringBuffer和StringBuilder
- String、StringBuffer和StringBuilder
- String、StringBuffer和StringBuilder
- String StringBuffer和StringBuilder
- String、StringBuffer和StringBuilder
- String和StringBuffer,StringBuilder
- String、StringBuffer和StringBuilder
- String, StringBuffer和 StringBuilder
- mysql中having和where的区别
- bug日记2016.12.01
- 验证码识别打码程序接口示例
- QT设置程序图标
- HDU3499Flight(双向Dijkstra)
- String和StringBuilder和StringBuffer三兄弟
- Tomcat 生产服务器性能优化
- nullptr和NULL的区别
- 发送RTP封装的g711流,并用VLC接收的注意事项
- openstack网络节点的迁移
- WinCE学习路线
- [编程题] 买苹果
- Eigen复矩阵的使用[微记]
- OverFeat心得