赞
踩
String和StringBuilder的底层都是char数组
但是String的char[] 是final修饰的,只能被赋值一次
StringBuilder的char[]数组没有final修饰,是可以被多次赋值的
在StringBuilder中char[] value的赋值,实际上是给StringBuilder构造出来的字符串进行内容的改变。
改变内容是通过数组的扩容,然后指向扩容后的数组来改变数组的内容,从而达到改变字符串内容的效果。
String类型的字符串,一旦定义就不可以改变。
// 无参构造 public StringBuilder() { super(16); } 无参构造的实现,给我们一个什么信息? 1. StringBuilder的父类是AbstractStringBuilder 2. 它的构造方法直接调用了父类的有参构造 3. 父类的有参构造原型应该是: public AbstractStringBuilder(int capacity) { this.value = new char[capacity]; } 4. super(16)告诉我们,无参的StringBuilder()构造出来的StringBuider对象 中,char[] value数组的初始大小是:16 这样就是说,StringBuilder默认的字符串长度是16 // String类型的对象作为参数 public StringBuilder(String str) { super(str.length() + 16); append(str); } 如果传入的是字符串,那么构造出来的字符串长度应该是传入的 字符串长度+16 补充: java1.9以后,String和StringBuffer、StringBuilder的底层都由原来的char[]数组变成了byte[]数组。 为什么要这么做?底层有char[] 改成byte[]有什么用?节省了一半的空间。节省空间。 StringBuilder中: 底层的char[] value,问,该数组的作用是什么? 1.char[] value数组在StringBuilder中,就是一个缓存。 2.它可以被多次赋值,但只能指向一个数组对象 3.一旦改变它的指向,原来指向的那个数组对象被GC回收。 4.所以,不论怎么追加字符,改变字符串的内容长度,实际上是这样的: 在原来数组的大小之上建立新数组 将原来数组的内容拷贝到新数组中 将追加的内容放入新数组中 将引用指向新的数组 原来的数组被回收
在日常开发中,大家往往喜欢对字符串进行拼接。
String str = "12";
String str1 = str + "3";
str1 = str1 + "4";
这样做不好,浪费空间。实际对于开者来说,只是想要具体的结果。
这种做法浪费存储空间。
正确的做法是通过StringBuilder或者是StringBuffer来进行字符串的拼接
因为StringBuilder和StringBuffer底层有一个字符缓存数组。
追加的字符串,不会直接放入字符串常量池中。会先放入堆中的字符数组中。
直到调用toString方法才将最后的结果一次性存入到方法区内存中的字符串常量池中。
因为,只有String类型的才存放到常量池中。
StringBuilder和StringBuffer,不是String类型的。
public class StringBufferTest01 { public static void main(String[] args) { StringBuilder stringBuilder = new StringBuilder("abc"); System.out.println(stringBuilder.capacity()); stringBuilder.append("d"); // abcd stringBuilder.append("e");// abcde stringBuilder.append("f");// abcdef stringBuilder.append("g"); // abcdfeg // "abc" d e f g abcdefg System.out.println(stringBuilder); String str = "abc"; String str1 = str + "d"; str1 = str1 + "e"; str1 = str1 + "f"; str1 = str1 + "g"; // abc abcd abcde abcdef abcdefg d e f g } } 在以后开发过程中,使用到字符串的时候,推荐使用 String = "xxx" 在进行字符串拼接的时候,尽量少使用"+"去拼接,而是通过StringBuilder或者是StringBuffer 中的append()方法来进行字符串的拼接。 源码追踪图如下:
@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);// value.length = 16
}
// Create a copy, don't share the array 重新创建了一个String对象。不是共享。
// 这个方法被调用以后,方法区内存中的字符串常量池里才会有一个String常量。
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("d");
System.out.println(stringBuilder);// Object类型
System.out.println(stringBuilder.toString());// String类型
// 上面两个不是一回事
String string = "a";
System.out.println(string);/// String类型
System.out.println(string.toString());// String类型
// 这两个才是一回事
他们不是一回事,StringBuilder构造出来的是StringBuilder的对象,这个对象只有toString()之后,才是String类型的字符串。 所以StringBuilder构造出来的对象,不会放在方法区字符串常量池中。只有当他调用toString方法的时候,才会被转换为字符串,字符串最后都会放入到方法区内存的字符串常量池中。 我们不希望,常量池不断地被占用,如果用字符串直接拼接的方式,是不好,这样会造成常量池内存空间的大量占用。那么我们可以使用StringBuilder和StringBuffer来进行字符串的拼接,最后再将他们toString之后,将最后的那一个结果放入到常量池中。这样做节省常量池的空间。 什么时候使用StringBuilder? /* String string1 = "中华人民共和国"; String lr = "湖南省长沙市" + string1; String xr = "新疆自治区" + string1; address(lr); */ StringBuilder st = new StringBuilder("中华人民共和国"); StringBuilder zhangjiajie = st.append("湖南省长沙市"); // "中华人民共和国湖南省长沙市" --- 这个拼接后的结果存在于堆中,它是StringBuilder对象 // 它不是String对象。要将它转成String对象,只有一个方式,调用toString()方法。 // 调用了toString方法以后,实际是在底层通过StringBuilder的char[] value, // 和数组中的内容创建了一个新的String对象。 String lr = zhangjiajie.toString(); address(lr);
StringBuffer是线程安全的
StringBuilder不是线程安全的
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。