- String
- 字符串
- 不可变的字符序列
- 在 jdk1.8,我们底层用 char [ ] 存储
- 在 jdk 17,我们底层用 byte [ ] 存储
- StringBuffer
- 字符串缓冲区类
- 可变的字符序列,线程安全的(synchronized),效率低
- 在 jdk1.8,我们底层用 char [ ] 存储
- 在 jdk 17,我们底层用 byte [ ] 存储
- StringBuilder
- 字符串生成器类
- 可变的字符序列,jdk5.0新增的,线程不安全的,效率高
- 在 jdk1.8,我们底层用 char [ ] 存储
- 在 jdk 17,我们底层用 byte [ ] 存储
1、那么在开发当中我们应该到底怎么选择呢?
- 首先看是不是一个多线程问题。
- 不是多线程问题,就用StringBuilder
- 因为只有多个线程操作共享数据的时候,我们才会考虑用StringBuffer
- 否则不是多线程,或者不存在多线程的安全问题,我们都建议用StringBuilder。
2、jdk8源码分析String
- String str = new String(); //char[ ] value = new char[0];
- String str1 = new String("abc") //char[ ] value = new char[ ]{ 'a', 'b', 'c' };
3、jdk8源码分析StringBuffer
- StringBuffer sb1 = new StringBuffer(); //char[ ] value = new char[16]; 底层创建了一个长度是16的数组。
- sb1.append('a'); //value[0] = 'a';
- sb1.append('b') //value[1] = 'b';
package stringdemo; public class StringBufferTest { public static void main(String[] args) { StringBuffer sb = new StringBuffer(); System.out.println(sb.capacity());//16 } } D:\Java\jdk-17\bin\java.exe "-javaagent:D:\BaiduNetdiskDownload\IntelliJ IDEA 2023.2\lib\idea_rt.jar=34469:D:\BaiduNetdiskDownload\IntelliJ IDEA 2023.2\bin" -Dfile.encoding=UTF-8 -classpath F:\IdeaProjects\JavaSenior\out\production\Exception stringdemo.StringBufferTest 16 Process finished with exit code 0
- StringBuffer sb2 = new StringBuffer(“abc”);//char[ ] value= new char["abc".length()+16]
package stringdemo; public class StringBufferTest { public static void main(String[] args) { StringBuffer sb1 = new StringBuffer("abc"); System.out.println(sb1.capacity());//3+16=19 } } D:\Java\jdk-17\bin\java.exe "-javaagent:D:\BaiduNetdiskDownload\IntelliJ IDEA 2023.2\lib\idea_rt.jar=35502:D:\BaiduNetdiskDownload\IntelliJ IDEA 2023.2\bin" -Dfile.encoding=UTF-8 -classpath F:\IdeaProjects\JavaSenior\out\production\Exception stringdemo.StringBufferTest 19 Process finished with exit code 03.1、扩容问题
- 如果要添加的数据底层数组盛不下了,那就需要扩容底层的数组。
- 默认情况下,扩容为原来容量的2倍+2,同时将原有数组中的元素赋值到新的数组中。
- new StringBuilder(); 创建的时候是不会扩容的,容量是(字符串参数的长度 加上16)。
package stringdemo; public class StringBufferTest { public static void main(String[] args) { //new StringBuffer();创建的时候是不会扩容的 StringBuffer sb1 = new StringBuffer("66666666666666666666666666666666666666666666666666666666"); System.out.println(sb1.length());//56 System.out.println(sb1.capacity());//56+16=72 } } D:\Java\jdk-17\bin\java.exe "-javaagent:D:\BaiduNetdiskDownload\IntelliJ IDEA 2023.2\lib\idea_rt.jar=37260:D:\BaiduNetdiskDownload\IntelliJ IDEA 2023.2\bin" -Dfile.encoding=UTF-8 -classpath F:\IdeaProjects\JavaSenior\out\production\Exception stringdemo.StringBufferTest 56 72 Process finished with exit code 0
- sb1.append();的时候,追加的时候才会发生扩容。超出(字符串参数的长度+16)的时候才会发生扩容。
public class StringBufferTest { public static void main(String[] args) { StringBuffer sb1 = new StringBuffer("44444444");//new创建的时候不会发生扩容 System.out.println(sb1.length());//8 System.out.println(sb1.capacity());//8+16=24 System.out.println("==================="); sb1.append("44444444"); System.out.println(sb1.length());//16 System.out.println(sb1.capacity());//24 System.out.println("==================="); sb1.append("44444444"); System.out.println(sb1.length());//24 System.out.println(sb1.capacity());//24 这个时候StringBuffer的容量已经满,再append就会扩容 System.out.println("==================="); sb1.append("4"); System.out.println(sb1.length());//25 System.out.println(sb1.capacity());//24*2+2=50 扩容为原来容量的2倍+2 } } D:\Java\jdk-17\bin\java.exe "-javaagent:D:\BaiduNetdiskDownload\IntelliJ IDEA 2023.2\lib\idea_rt.jar=37603:D:\BaiduNetdiskDownload\IntelliJ IDEA 2023.2\bin" -Dfile.encoding=UTF-8 -classpath F:\IdeaProjects\JavaSenior\out\production\jdk8 StringBufferTest 8 24 =================== 16 24 =================== 24 24 =================== 25 50 Process finished with exit code 0
3.2、指导意见
- 开发中建议大家使用:StringBuffer(int capacity),为了避免扩容,一开始建议使用带参数的构造器,效率会高一些。
4、StringBuffer类常用方法
- StringBuffer append(xxx):
- 提供了很多的append()方法,用于进行字符串拼接
- StringBuffer delete(int start,int end):
- 删除指定位置的内容
- StringBuffer replace(int start,int end,String str):
- 把[start,end]位置替换为str
- StringBuffer insert(int offset,xxx):
- 在指定位置插入xxx
- StringBuffer reverse():
- 把当前字符序列逆转
- 当append和insert时,如果原来value数组长度不够,可扩容。
- 如上这些方法支持方法链操作
总结
- 增:
- append(xxx)
- 删:
- delete(int start,int end)
- 改:
- setCharAt(int n,char ch) / replace(int start,int end,String str)
- 查:
- charAt(int n)
- 插:
- insert(int offset,xxx)
- 长度:
- length();
- *遍历
- for() + charAt() / toString()
5、对比String、StringBuffer、StringBuilder三者的效率:
- 从高到低排列:StringBuilder > StringBuffer > String
public class Efficiency { public static void main(String[] args) { long startTime = 0L; long endTime = 0L; String text = ""; StringBuffer buffer = new StringBuffer(""); StringBuilder builder = new StringBuilder(""); startTime = System.currentTimeMillis(); for (int i = 0; i < 20000; i++) { buffer.append(String.valueOf(i)); } endTime = System.currentTimeMillis(); System.out.println("StringBuffer的执行时间:" + (endTime - startTime)); startTime = System.currentTimeMillis(); for (int i = 0; i < 20000; i++) { builder.append(String.valueOf(i)); } endTime = System.currentTimeMillis(); System.out.println("StringBuilder的执行时间:" + (endTime - startTime)); startTime = System.currentTimeMillis(); for (int i = 0; i < 20000; i++) { text = text + i; } endTime = System.currentTimeMillis(); System.out.println("String的执行时间:" + (endTime - startTime)); } } D:\Java\jdk-17\bin\java.exe "-javaagent:D:\BaiduNetdiskDownload\IntelliJ IDEA 2023.2\lib\idea_rt.jar=18779:D:\BaiduNetdiskDownload\IntelliJ IDEA 2023.2\bin" -Dfile.encoding=UTF-8 -classpath F:\IdeaProjects\JavaSenior\out\production\jdk8 Efficiency StringBuffer的执行时间:5 StringBuilder的执行时间:3 String的执行时间:210 Process finished with exit code 0
本文比较了Java中String、StringBuffer和StringBuilder在内存存储、线程安全性和效率方面的差异,建议在非多线程场景下优先使用StringBuilder,以提高性能。





155

被折叠的 条评论
为什么被折叠?



