JDK源码阅读-------自学笔记(十二)(java.lang.StringBuffer和StringBuilder比较)
StringBuilder结构
- 明显的看到StringBuilder跟String相似的存在char数组
- 区别是StringBuilder的char[]数组不是final修饰的,所以是可以多次改变的,随时可以改变源码
1 abstract class AbstractStringBuilder implements Appendable, CharSequence { 2 /** 3 * The value is used for character storage. 4 */ 5 char[] value; 6 7 ....
核心要点
- final的有无区别
- 可以成为可变的字符序列
StringBuffer结构
- 明显的看到StringBuffer跟String相似的存在char数组
- 区别是StringBuffer的char[]数组不是final修饰的,所以是可以多次改变的,随时可以改变源码
1 abstract class AbstractStringBuilder implements Appendable, CharSequence { 2 /** 3 * The value is used for character storage. 4 */ 5 char[] value; 6 7 .... 8 }
核心要点
- final的有无区别
- 可以成为可变的字符序列
StringBuffer和StringBuilder区别
不同:
- StringBuffer线程安全,效率低
- StringBuilder线程不安全,效率高
- 一般使用StringBuilder,因为一般不涉及线程安全
相同:
- 都是AbstractStringBuilder子类
实例:
可变字符序列,内容可以随意修改
1 StringBuilder stringBuilder = new StringBuilder("abcdfg"); 2 3 System.out.println(Integer.toHexString(stringBuilder.hashCode())); 4 5 System.out.println(stringBuilder); 6 7 8 stringBuilder.setCharAt(3, 'L'); 9 System.out.println(Integer.toHexString(stringBuilder.hashCode())); 10 11 System.out.println(stringBuilder);
基本用法
- 添加26个字母
1 // 初始化StringBuffer 2 StringBuffer twentySixLetter = new StringBuffer(); 3 4 for (int i = 0; i < 26; i++) { 5 6 // 字符增加 7 char needTransformationLetter = (char) ('a' + i); 8 9 // 添加字母到stringBuffer 10 twentySixLetter.append(needTransformationLetter); 11 12 } 13 14 System.out.println("打印26个字母:" + twentySixLetter);
- 倒叙字符序列
1 twentySixLetter.reverse(); 2 3 System.out.println("打印26个字母的倒叙:" + twentySixLetter);
- 修改制定位置的字符
1 twentySixLetter.setCharAt(6,'走'); 2 System.out.println("修改第六个位置的字符:" + twentySixLetter);
- 指定位置插入字符
1 twentySixLetter.insert(0,'再'); 2 System.out.println("在第一个位置插入字符:" + twentySixLetter);
注:
观察源码
// 继承父类方法
super.insert(offset, c);
// 返回本身对象
return this;
这就意味着可以多次的使用这个对象,一般称之为 链式调用
核心就是:
调用了 return this;
如下:
1 // 指定位置插入字符 2 twentySixLetter.insert(0,'再').insert(1,'三'); 3 System.out.println("在第一个位置插入字符:" + twentySixLetter);
- 删除某个区间的字符,或删除某个位置的字符 delete也是链式调用,也可以连续删除
1 // 删除区间字符 2 twentySixLetter.delete(20,26); 3 System.out.println("删除后的字符:" + twentySixLetter);
- 删除某个字符
1 //删除某个字符 2 twentySixLetter.deleteCharAt(0).deleteCharAt(0); 3 System.out.println("删除第一个第二个字符:" + twentySixLetter);
- 获取某个字符
1 //获取字符 2 twentySixLetter.charAt(15); 3 System.out.println("获取字符:" + twentySixLetter);
不可变和可变字符序列使用陷阱
- 循环累加字符串的时候,不建议如下写法,会创建大量对象,占用过多资源,消耗服务器资源
1 String wrongWriteString = ""; 2 3 for (int i = 0; i < 5000; i++) { 4 5 //相当于产生了10000个对象 6 wrongWriteString = wrongWriteString + i; 7 } 8 9 System.out.println(wrongWriteString);
- 建议如下写法,可以减少创建对象和所消耗的时间
1 StringBuilder stringBuilderRight = new StringBuilder(""); 2 3 for (int i = 0; i < 5000; i++) { 4 stringBuilderRight.append(i); 5 } 6 7 System.out.println(stringBuilderRight);
- 效率,占用内存测试
1 // 使用String进行字符串的拼接 2 String stringWrong = ""; 3 //本质上使用StringBuilder拼接, 但是每次循环都会生成一个StringBuilder对象 4 //获取系统剩余内存空间 5 long num1 = Runtime.getRuntime().freeMemory(); 6 //获取系统的当前时间 7 long time1 = System.currentTimeMillis(); 8 for (int i = 0; i < 5000; i++) { 9 //相当于产生了10000个对象 10 stringWrong = stringWrong + i; 11 } 12 long num2 = Runtime.getRuntime().freeMemory(); 13 long time2 = System.currentTimeMillis(); 14 System.out.println("String占用内存 : " + (num1 - num2)); 15 System.out.println("String占用时间 : " + (time2 - time1)); 16 17 18 /**使用StringBuilder进行字符串的拼接*/ 19 StringBuilder stringBuilderRight = new StringBuilder(""); 20 long num3 = Runtime.getRuntime().freeMemory(); 21 long time3 = System.currentTimeMillis(); 22 for (int i = 0; i < 5000; i++) { 23 stringBuilderRight.append(i); 24 } 25 long num4 = Runtime.getRuntime().freeMemory(); 26 long time4 = System.currentTimeMillis(); 27 System.out.println("StringBuilder占用内存 : " + (num3 - num4)); 28 System.out.println("StringBuilder占用时间 : " + (time4 - time3));
十年磨一剑,一剑破万法