在解析StringBuilder类之前,我们先对String类做一个简单的分析。不过分析之前先想一个问题,为什么有好好的String类不用,要专用StringBuilder类呢?
5分钟之后。。。。。。。。。。。。。。。。。。。。。。。。。。。
1. String类简介
1.1. String(字符串常量)概述
String类在API中是这样描述:
String 类代表字符串
。Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现
。
字符串是常量;它们的值在创建之后不能更改。
字符串缓冲区支持可变的字符串。因为 String 对象是不可变的,所以可以共享。
java.lang.String:
public final class String
implements java.io.Serializable, Comparable, CharSepuence
1.2. 分析String源码
1.2.1. String的成员变量
String的成员变量
/** String的属性值 */
private final char value[];
/** The offset is the first index of the storage that is used. */
/**数组被使用的开始位置**/
private final int offset;
/** The count is the number of characters in the String. */
/**String中元素的个数**/
private final int count;
/** Cache the hash code for the string */
/**String类型的hash值**/
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
/**
* Class String is special cased within the Serialization Stream Protocol.
*
* A String instance is written into an ObjectOutputStream according to
* <a href="{@docRoot}/../platform/serialization/spec/output.html">
* Object Serialization Specification, Section 6.2, "Stream Elements"</a>
*/
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
- 从源码看出String底层使用一个字符数组来维护的。
- 从成员变量可以知道String类的值是final类型的,不能被改变的,所以只要一个值改变就会生成一个新的String类型对象,存储String数据也不一定从数组的第0个元素开始的,而是从offset所指的元素开始。
1.2.2. 创建字符串的方式
-
直接赋值方式创建对象(
在方法区的常量池中
)String str = "hello"; //直接赋值方式
-
通过构造方法创建字符串对象(
在堆内存中
)String str = new String("hello"); // 实例化方法
1.3. 字符串拼接问题(StringBuilder的引出)
由于String类的对象内容不可改变,所以每当进行字符串拼接时,总是会在内存中创建一个新的对象。例如:
public class StringDemo {
public static void main(String[] args) {
String value1 = "a";
String value2 = "b";
String value3 = "c";
String s = value1 + value2 + value3;
System.out.println(s); // "abc"
}
}
在API中对String类有这样的描述:字符串是常量,它们的值在创建后不能被更改。
根据这句话分析我们的代码,其实总共产生了5个字符串,即"a"
、"b"
、"c"
、"ab"
和"abc"
。引用变量s首先指向a
对象,最终指向拼接出来的新字符串对象,即abc
。
由此可知,如果对字符串进行拼接操作,每次拼接,都会构建一个新的String对象,既耗时,又浪费空间。为了解决这一问题,可以使用java.lang.StringBuilder
类。
2. StringBuilder概述
查阅java.lang.StringBuilder
的API,StringBuilder又称为可变字符序列,它是一个类似于 String 的字符串缓冲区,通过某些方法调用可以改变该序列的长度和内容。
原来StringBuilder是个字符串的缓冲区,即它是一个容器,容器中可以装很多字符串。并且能够对其中的字符串进行各种操作。
它的内部拥有一个组用来存放字符串内容,进行字符串拼接时,直接在数组中加入新内容。StringBuilder会自动维护数组的扩容。原理如下图所示:(默认16字符空间,超过自动扩充)
2.1. 构造方法
根据StringBuilder的API文档,常用构造方法有2个:
public StringBuilder()
:构造一个空的StringBuilder容器。public StringBuilder(String str)
:构造一个StringBuilder容器,并将字符串添加进去。
public class StringBuilderDemo {
public static void main(String[] args) {
StringBuilder sb1 = new StringBuilder();
System.out.println(sb1); // (空白)
// 使用带参构造
StringBuilder sb2 = new StringBuilder("hello");
System.out.println(sb2); // hello
}
}
2.2. 常用方法
StringBuilder常用的方法有2个:
public StringBuilder append(...)
:添加任意类型数据的字符串形式,并返回当前对象自身。public String toString()
:将当前StringBuilder对象转换为String对象。
2.2.1. append方法
append方法具有多种重载形式,可以接收任意类型的参数。任何数据作为参数都会将对应的字符串内容添加到StringBuilder中。例如:
public class Demo02StringBuilder {
public static void main(String[] args) {
//创建对象
StringBuilder builder = new StringBuilder();
//public StringBuilder append(任意类型)
// append方法返回的是this,调用方法的对象builder,this==builder
StringBuilder builder2 = builder.append("hello");
//对比一下
System.out.println("builder:"+builder);
System.out.println("builder2:"+builder2);
System.out.println(builder == builder2); //true
// 可以添加 任何类型
builder.append("hello");
builder.append("world");
builder.append(true);
builder.append(100);
// 在我们开发中,会遇到调用一个方法后,返回一个对象的情况。然后使用返回的对象继续调用方法。
// 这种时候,我们就可以把代码现在一起,如append方法一样,代码如下
//链式编程:方法返回值是一个对象,可以继续调用方法
builder.append("hello").append("world").append(true).append(100);
System.out.println("builder:"+builder);
}
}
备注:StringBuilder已经覆盖重写了Object当中的toString方法。
2.2.2. toString方法
通过toString方法,StringBuilder对象将会转换为不可变的String对象。如:
public class Demo16StringBuilder {
public static void main(String[] args) {
// 链式创建
StringBuilder sb = new StringBuilder("Hello").append("World").append("Java");
// 调用方法
String str = sb.toString();
System.out.println(str); // HelloWorldJava
}
}
总结:
StringBuilder和String可以相互转换:String -> StringBuilder : 可以使用StringBuilder的构造方法 :
StringBuilder(String str) 构造一个字符串生成器,并初始化为指定的字符串内容
StringBuilder -> String : 可以使用StringBuilder中的toString方法 :
public String toString() : 将当前StringBuilder对象转换为String对象。