StringBuilder和StringBuffer
1、概述
StringBuilder 是一个可变的字符序列。它继承于AbstractStringBuilder,实现了CharSequence接口。
StringBuffer 也是继承于AbstractStringBuilder的子类;但是,StringBuilder和StringBuffer不同,前者
是非线程安全的,后者是线程安全的。
2、常用方法
1、insert
package com.kuang.oop;
import java.util.HashMap;
public class Test {
public static void main(String args[]) {
System.out.println("---------- testInsertAPIs -----------");
StringBuilder sbuilder = new StringBuilder();
// 在位置0处插入字符数组
sbuilder.insert(0, new char[] { 'a', 'b', 'c', 'd', 'e' });
System.out.println(sbuilder);// abcde
// 在位置0处插入字符数组。0表示字符数组起始位置,3表示长度
sbuilder.insert(0, new char[] { 'A', 'B', 'C', 'D', 'E' }, 0, 3);
System.out.println(sbuilder);// ABCabcde
// 在位置0处插入float
sbuilder.insert(0, 1.414f);
System.out.println(sbuilder);// 1.414ABCabcde
// 在位置0处插入double
sbuilder.insert(0, 3.14159d);// 3.141591.414ABCabcde
// 在位置0处插入boolean
sbuilder.insert(0, true);// true3.141591.414ABCabcde
// 在位置0处插入char
sbuilder.insert(0, '/n');// 换行以后加上true3.141591.414ABCabcde
System.out.println(sbuilder);
// 在位置0处插入int
sbuilder.insert(0, 100);
System.out.println(sbuilder);// 100换行以后加上true3.141591.414ABCabcde
// 在位置0处插入long
sbuilder.insert(0, 12345L);//以下省略
// 在位置0处插入StringBuilder对象
sbuilder.insert(0, new StringBuilder("StringBuilder"));
// 在位置0处插入StringBuilder对象。6表示被在位置0处插入对象的起始位置(包括),13是结束位置(不包括)
sbuilder.insert(0, new StringBuilder("STRINGBUILDER"), 6, 13);
// 在位置0处插入StringBuffer对象。
sbuilder.insert(0, new StringBuffer("StringBuffer"));
// 在位置0处插入StringBuffer对象。6表示被在位置0处插入对象的起始位置(包括),12是结束位置(不包括)
sbuilder.insert(0, new StringBuffer("STRINGBUFFER"), 6, 12);
// 在位置0处插入String对象。
sbuilder.insert(0, "String");
// 在位置0处插入String对象。1表示被在位置0处插入对象的起始位置(包括),6是结束位置(不包括)
sbuilder.insert(0, "0123456789", 1, 6);
System.out.println(sbuilder);
/*
* 12345StringBUFFERStringBufferBUILDERStringBuilder12345100
* true3.141591.414ABCabcde
*/
sbuilder.insert(0, '/n');
// 在位置0处插入Object对象。此处以HashMap为例
HashMap map = new HashMap();
map.put("1", "one");
map.put("2", "two");
map.put("3", "three");
sbuilder.insert(0, map);
System.out.printf("%s/n/n", sbuilder);
// {1=one, 2=two, 3=three}
// 12345StringBUFFERStringBufferBUILDERStringBuilder12345100
// true3.141591.414ABCabcde
}
}
2、append
package com.kuang.oop;
import java.util.HashMap;
public class Test {
public static void main(String args[]) {
/**
* StringBuilder 的append()示例
*/
System.out.println("------------------- testAppendAPIs -----------------");
StringBuilder sbuilder = new StringBuilder();
// 追加字符数组
sbuilder.append(new char[] { 'a', 'b', 'c', 'd', 'e' });
// 追加字符数组。0表示字符数组起始位置,3表示长度
sbuilder.append(new char[] { 'A', 'B', 'C', 'D', 'E' }, 0, 3);
// 追加float
sbuilder.append(1.414f);
// 追加double
sbuilder.append(3.14159d);
// 追加boolean
sbuilder.append(true);
// 追加char
sbuilder.append('/n');
// 追加int
sbuilder.append(100);
// 追加long
sbuilder.append(12345L);
// 追加StringBuilder对象
sbuilder.append(new StringBuilder("StringBuilder"));
// 追加StringBuilder对象。6表示被追加对象的起始位置(包括),13是结束位置(不包括)
sbuilder.append(new StringBuilder("STRINGBUILDER"), 6, 13);
// 追加StringBuffer对象。
sbuilder.append(new StringBuffer("StringBuffer"));
// 追加StringBuffer对象。6表示被追加对象的起始位置(包括),12是结束位置(不包括)
sbuilder.append(new StringBuffer("STRINGBUFFER"), 6, 12);
// 追加String对象。
sbuilder.append("String");
// 追加String对象。1表示被追加对象的起始位置(包括),6是结束位置(不包括)
sbuilder.append("0123456789", 1, 6);
sbuilder.append('/n');
// 追加Object对象。此处以HashMap为例
HashMap map = new HashMap();
map.put("1", "one");
map.put("2", "two");
map.put("3", "three");
sbuilder.append(map);
sbuilder.append('/n');
// 追加unicode编码
sbuilder.appendCodePoint(0x5b57); // 0x5b57是“字”的unicode编码
sbuilder.appendCodePoint(0x7b26); // 0x7b26是“符”的unicode编码
sbuilder.appendCodePoint(0x7f16); // 0x7f16是“编”的unicode编码
sbuilder.appendCodePoint(0x7801); // 0x7801是“码”的unicode编码
System.out.printf("%s/n/n", sbuilder);
}
}
------------------- testAppendAPIs -----------------
abcdeABC1.4143.14159true
10012345StringBuilderBUILDERStringBufferBUFFERString12345
{1=one, 2=two, 3=three}
字符编码
3、replace
package com.kuang.oop;
public class Test {
public static void main(String args[]) {
System.out.println("------------------- testReplaceAPIs-------------------");
StringBuilder sbuilder;
sbuilder = new StringBuilder("0123456789");
sbuilder.replace(0, 3, "ABCDE");
System.out.println(sbuilder);// 用ABCDE替换了012
sbuilder = new StringBuilder("0123456789");
sbuilder.reverse();
System.out.printf("sbuilder=%s/n", sbuilder);// 反转为9876543210
sbuilder = new StringBuilder("0123456789");
sbuilder.setCharAt(0, 'M');
System.out.printf("sbuilder=%s/n", sbuilder);// M123456789
System.out.println();
}
}
4、delete
package com.kuang.oop;
public class Test {
public static void main(String args[]) {
System.out.println("------------------- testDeleteAPIs-------------------");
StringBuilder sbuilder;
sbuilder = new StringBuilder("0123456789");
// 删除位置0的字符,剩余字符是“123456789”。
sbuilder.deleteCharAt(0);
// 删除位置3(包括)到位置6(不包括)之间的字符,剩余字符是“sb=123789”。
sbuilder.delete(3, 6);
// 获取sb中从位置1开始的字符串,23789
String str1 = sbuilder.substring(1);
// 获取sb中从位置3(包括)到位置5(不包括)之间的字符串,
String str2 = sbuilder.substring(3, 5);
// 获取sb中从位置3(包括)到位置5(不包括)之间的字符串,获取的对象是CharSequence对象,此处转型为String
String str3 = (String) sbuilder.subSequence(3, 5);
System.out.printf("sbuilder=%s/nstr1=%s/nstr2=%s/nstr3=%s/n", sbuilder, str1, str2, str3);
}
}
5、index
package com.kuang.oop;
public class Test {
public static void main(String args[]) {
StringBuilder sbuilder = new StringBuilder("abcAbcABCabCaBcAbCaBCabc");
System.out.printf("sbuilder=%s/n", sbuilder);
// 1. 从前往后,找出"bc"第一次出现的位置,1
System.out.printf("%-30s = %d/n", "sbuilder.indexOf(/"bc/")",
sbuilder.indexOf("bc"));
// 2. 从位置5开始,从前往后,找出"bc"第一次出现的位置,22
System.out.printf("%-30s = %d/n", "sbuilder.indexOf(/"bc/", 5)",
sbuilder.indexOf("bc", 5));
// 3. 从后往前,找出"bc"第一次出现的位置,22
System.out.printf("%-30s = %d/n", "sbuilder.lastIndexOf(/"bc/")",
sbuilder.lastIndexOf("bc"));
// 4. 从位置4开始,从后往前,找出"bc"第一次出现的位置,4
System.out.printf("%-30s = %d/n", "sbuilder.lastIndexOf(/"bc/", 4)",
sbuilder.lastIndexOf("bc", 4));
System.out.println();
}
}
6、其他API
package com.kuang.oop;
public class Test {
public static void main(String args[]) {
System.out.println("----------- testOtherAPIs -----------");
StringBuilder sbuilder = new StringBuilder("0123456789");
int cap = sbuilder.capacity();
System.out.printf("cap=%d/n", cap);// 26
/*
* capacity()返回的是字符串缓冲区的容量,如下:
* StringBuffer( ); 分配16个字符的缓冲区
* StringBuffer( int len ); 分配len个字符的缓冲区
* StringBuffer( String s ); 除了按照s的大小分配空间外,再分配16个 字符的缓冲区
* 你的StringBuffer是用字符构造的,"0123456789"的长度是10另外再分配16个字符,所
* 以一共是26。
*/
char c = sbuilder.charAt(6);
System.out.printf("c=%c/n", c);// 转换为字符6
char[] carr = new char[4];
sbuilder.getChars(3, 7, carr, 0);// [3,7)
for (int i = 0; i < carr.length; i++) {
System.out.printf("carr[%d]=%c ", i, carr[i]);// carr[0]=3 carr[1]=4 carr[2]=5 carr[3]=6
}
System.out.println();
}
}
3、StringBuffer
和StringBulider用法差不多,不过多介绍,主要看一下三者的区别
4、小结
【String、StringBuffer、StringBuilder之间的区别】
首先需要说明的是:
- String 字符串常量
- StringBuffer 字符串变量(线程安全)
- StringBuilder 字符串变量(非线程安全)
在大多数情况下三者在执行速度方面的比较:StringBuilder > StringBuffer > String
解释:
String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String
类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以
经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中
无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。
而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而
不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对
象经常改变的情况下。
为什么是大多数情况呢?
在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,
所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中,
String 效率是远要比 StringBuffer 快的:
String S1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuilder(“This is only a”).append(“
simple”).append(“ test”);
你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本
一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个
String S1 = “This is only a” + “ simple” + “test”;
其实就是:String S1 = “This is only a simple test”;
所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象
的话,速度就没那么快了,譬如:
String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
大部分情况下StringBuilder的速度要大于StringBuffer:
java.lang.StringBuilder一个可变的字符序列是5.0新增的。(大多数情况下就是我们是在单线程下进行
的操作,所以大多数情况下是建议用StringBuilder而不用StringBuffer的)此类提供一个与 StringBuffer
兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个
线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比
StringBuffer 要快。两者的方法基本相同。
对于三者使用的总结:
1)如果要操作少量的数据用 = String
2)单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
3)多线程操作字符串缓冲区 下操作大量数据 = StringBuffer
5、面试题
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/279997.html