1.StringBuilder类概述
StringBuffer类和StringBuilder类非常类似,都是继承自抽象类AbstractStringBuilder类,均代表可变的Unicode字符序列。StringBuilder类和StringBuffer类方法几乎一模一样,不过StringBuilder不是线程安全的,这是和StringBuffer的主要区别:
-
StringBuffer线程安全,做线程同步检查,效率较低。
-
StringBuilder线程不安全,不做线程同步检查,因此效率较高(推荐使用)。
因为JDK1.5版本之前只有一个StringBuffer类(线程安全),由于发现利用多线程对同一字符串数据操作的情况是很少的,为了提高效率JDK1.5以后就有了StringBuilder类,StringBuilder类提供一个与StringBuffer兼容的API,所以StringBuilder类和StringBuffer类的方法和功能完全一致。
目前,我们还没有涉及到线程与同步,知道结论 StringBuilder 比 StringBuffer 快即可。
2.字符串拼接优化
对于常量做字符串拼接操作时,对于编译期就能确定的值,编译器会将值合并。
【示例】常量做字符串拼接
public class Test {
public static void main(String[] args) {
test01();
test02();
}
/**
* 直接量拼接,对于编译期就能确定的值,编译器会将值合并
* String hw = "hello" + "world";反编译class
* 我们将看到 : String hw = "helloworld";
*
* 所以hw == helloWorld 输出true
*/
public static void test01() {
String hw = "hello" + "world"; // 等于:String hw = "helloworld";
String helloWolrd = "helloworld";
System.out.println(hw == helloWolrd); // 输出:true
}
/**
* String hw = h + "world";虽然包含变量 h的运算,但是编译器
* 对fianl变量在编译期能确定其值,会发生宏替换,即:h变量替换成其值"hello",
* 然后编译器会对直接量字串直接合并
* String hw = h + "world";在编译完后就变成了 String hw = "helloworld";
*
* 所以hw == helloWorld 输出true
*/
public static void test02() {
final String h = "hello"; // final修饰的是常量
String hw = h + "world"; // 等于:String hw = "helloworld";
String helloWolrd = "helloworld";
System.out.println(hw == helloWolrd); // 输出:true
}
}
对于变量做字符串拼接操作时,由于相加的变量中存放的是字符串的地址引用,因为在编译时无法确切地知道其他具体的值,也就没有办法对其进行优化处理,这时为了达到连接的效果,其内部采用了 StringBuilder 的机制进行处理(JDK 5 中新增的,我这里没有 JDK 1.4,估计在 JDK 1.4 下采用的是 StringBuffer),将他们都 append进去,最后用 toString 输出。
【示例】变量做字符串拼接操作
public class Test {
/**
* hw在编译期并不能确定值,因为h是变量,JVM在运行期才能确定其值
* 会在运行期时,进行字串拼接生成新的字串对象,通过javap -c Test查看虚拟机指令
* 我们发现String hw = h + "world";其实等效于:
* StringBuilder sb = new StringBuilder(h);
* sb.append("world");
* String hw = sb.toString();
*
* 所以hw == helloWorld 输出false
*/
public static void main(String[] args) {
String h = "hello";
String hw = h + "world";
String helloWolrd = "helloworld";
System.out.println(hw == helloWolrd); // 输出:false
}
}
3.字符串的效率比较
分别使用String、StringBuffer、StringBuilder进行10000次的字符串拼接操作,通过计算运行时间来分析执行的效率。
【示例】字符串拼接效率比较
public class StringBuilderDemo {
public static void main(String[] args) {
stringBuilderMethod(); // 测试StringBuilder耗时
stringBufferMethod(); // 测试StringBuffer耗时
stringMethod(); // 测试String耗时
}
// 测试String耗时
public static void stringMethod() {
String str = "";
long now1 = System.currentTimeMillis(); // 开始时间
for (int i = 0; i < 10000; i++) { // 进行10000次字符串拼接
str += i; // 相当于产生了10000个StringBuffer对象
}
long now2 = System.currentTimeMillis(); // 结束时间
System.out.println("String耗时:" + (now2 - now1) + "ms");
}
// 测试StringBuffer耗时
public static void stringBufferMethod() {
StringBuffer sb = new StringBuffer();
long now1 = System.currentTimeMillis(); // 开始时间
for (int i = 0; i < 10000; i++) { // 进行10000次字符串拼接
sb.append(i);
}
long now2 = System.currentTimeMillis(); // 结束时间
System.out.println("StringBuffer耗时:" + (now2 - now1) + "ms");
}
// 测试StringBuilder耗时
public static void stringBuilderMethod() {
StringBuilder sb = new StringBuilder();
long now1 = System.currentTimeMillis(); // 开始时间
for (int i = 0; i < 10000; i++) { // 进行10000次字符串拼接
sb.append(i);
}
long now2 = System.currentTimeMillis(); // 结束时间
System.out.println("StringBuilder耗时:" + (now2 - now1) + "ms");
}
}
以上代码执行结果为:
StringBuffer和StringBuilder的运行效率几乎一致,这是因为二者都是对对象本身进行操作,不会生成新的字符串对象。二者的区别主要是StringBuffer是线程安全的,而StringBuilder是线程不安全的,所以StringBuilder的运行效率略高于StringBuffer。
String是不可变的对象,每次对String进行操作的时候,都会生成一个新的对象(StringBuilder),占用大量内存空间,这会对系统的性能造成影响,执行效率最低。
所以在平时编程的过程中,如果字符串需要经常改变,应该尽量避免使用String。
4.对象方法链式调用
在我们日常开发中,会遇到调用一个方法后,返回一个对象的情况,这种设计允许用户连续的链式调用方法,从而实现按人的惯性思维进行快速开发,我们称之为链式语法。在我们学过的常用工具类中,StringBuffer类和StringBuilder类中的方法都是使用链式语法的典范,通过在方法添加return this的形式来实现方法的链式调用,我们打开StringBuilder的源码:
从源码中我们可以看到,我们每次调用StringBuilder类中的insert方法,都会返回当前可变字符串对象,然后我们可以使用返回的对象继续调用方法,从而实现了方法链式调用。
【示例】对象的方法链式调用案例
// 创建一个可变字符容器,用来存放数据
StringBuilder sb = new StringBuilder("hello-world");
// 通过链式语法操作可变字符串数据
sb.append("-WHSXT").insert(4, "AAA").delete(6, 8);
// 输出:"hellAA-world-WHSXT"
System.out.println(sb);
ps:如需最新的免费文档资料和教学视频,请添加QQ群(627407545)领取。