小伙子! 打起精神来, 让自己活的贵一点!
String 类, StringBuffer 类, StringBuilder 类三者之间的关系
String 类对字符串的保存格式:
private final char value[];
从源码中可以看出来, 它是被 final 修饰的, 是不可变的, 从它被创建直至被销毁, 它的字符序列都没有改变, 我们对它的一系列操作都是通过创建新的 String 对象来完成的.
String 的相关知识
StringBuilder,StringBuffer 两个类对字符串的保存格式:
char[] value;
StringBuilder,StringBuffer 两个类都继承自抽象类 AbstractStringBuilder, 它们是可变的.
StringBuilder,StringBuffer 与 String 类之间的转换
public abstract String toString();
当我们通过 StringBuilder,StringBuffer 对象进行一系列操作后得到了我们最终想要的字符串之后, 可以通过 toString()方法来将 StringBuilder,StringBuffer 对象转化为 String 对象.
StringBuilder a = new StringBuilder("hello");
同时也可以将 String 类型转换为 StringBuilder 或者 StringBuffer 类型.
线程安全相关的问题
String 类
String 中的对象是不可变的, 可以理解为常量, 显然线程安全.
StringBuffer 类与 StringBuilder 类
- public synchronized StringBuffer append(Object obj) {
- super.append(String.valueOf(obj));
- return this;
- }
- public synchronized StringBuffer reverse() {
- super.reverse();
- return this;
- }
从代码可以看出来 StringBuffer 类是被 synchronized 修饰的, 所以是线程安全的, StringBuffer 和 StringBuilder 类功能基本相似, 最大的区别在与 StringBuilder 是没有被 synchronized 修饰的, 因此线程不安全, 但是 StringBuilder 类的速度要比 String 类与 StringBuffer 要快一点.
StringBuffer 是线程安全的, 这意味着它们已经同步方法来控制访问, 以便只有一个线程可以在同一时间访问一个 StringBuffer 对象同步代码. 因此, StringBuffer 的对象通常在多线程环境中是安全的, 使用多个线程可以试图同时访问相同 StringBuffer 对象.
StringBuilder 类不是线程安全的. 由于不同步, StringBuilder 的性能可以比 StringBuffer 更好. 因此, 如果在单线程环境中工作, 使用 StringBuilder, 而不是 StringBuffer 可能会有更高的性能.
总结
String 字符串常量
StringBuffer 字符串变量(线程安全)
StringBuilder 字符串变量(非线程安全)
在大部分情况下速度: StringBuilder> StringBuffer
在大部分情况下速度: StringBuffer> String
速度测试代码
- public class Test {
- final static int time = 50000; // 循环次数
- public static void main(String[] args) {
- Test test = new Test();
- String s1 = "String 类测试:";
- StringBuffer st1 = new StringBuffer( "StringBuffer 类测试:");
- StringBuilder st2 = new StringBuilder( "StringBuilder 类测试:");
- test.test(s1);
- test.test(st1);
- test.test(st2);
- test.test2();
- test.test3();
- }
- /*
- * String 类测试方法
- */
- public void test(String s){
- long begin = System.currentTimeMillis();// 获取当前系统时间(毫秒数), 开始
- for(int i=0; i<time; i++){
- s += "hello";
- }
- long over = System.currentTimeMillis();// 获取当前系统时间(毫秒数), 结束
- System.out.println("操作"+s.getClass().getName()+"类型使用的时间为:"+(over-begin)+"毫秒");
- }
- /*
- * StringBuffer 类测试方法
- */
- public void test(StringBuffer s){
- long begin = System.currentTimeMillis();
- for(int i=0; i<time; i++){
- s.append("hello");
- }
- long over = System.currentTimeMillis();
- System.out.println("操作"+s.getClass().getCanonicalName()+"类型使用的时间为:"+(over-begin)+"毫秒");
- }
- /*
- * StringBuilder 类测试方法
- */
- public void test(StringBuilder s){
- long begin = System.currentTimeMillis();
- for(int i=0; i<time; i++){
- s.append("hello");
- }
- long over = System.currentTimeMillis();
- System.out.println("操作"+s.getClass().getName()+"类型使用的时间为:"+(over-begin)+"毫秒");
- }
- /* 对 String 直接进行字符串拼接的测试 */
- public void test2(){// 操作字符串对象引用相加类型使用的时间
- String s2 = "abcd";
- long begin = System.currentTimeMillis();
- for(int i=0; i<time; i++){
- String s = s2 + s2 +s2;
- }
- long over = System.currentTimeMillis();
- System.out.println("操作字符串对象引用相加类型使用的时间为:"+(over-begin)+"毫秒");
- }
- public void test3(){// 操作字符串相加使用的时间
- long begin = System.currentTimeMillis();
- for(int i=0; i<time; i++){
- String s = "abcd" + "abcd" + "abcd";
- }
- long over = System.currentTimeMillis();
- System.out.println("操作字符串相加使用的时间为:"+(over-begin)+"毫秒");
- }
- }
- // 测试结果:
操作 java.lang.String 类型使用的时间为: 9954 毫秒
操作 java.lang.StringBuffer 类型使用的时间为: 10 毫秒
操作 java.lang.StringBuilder 类型使用的时间为: 0 毫秒
操作字符串对象引用相加类型使用的时间为: 15 毫秒
操作字符串相加使用的时间为: 0 毫秒
结果可以看出, 在不必考虑到线程同步问题, 我们应该优先使用 StringBuilder 类; 如果要保证线程安全, 自然是 StringBuffer; 能直接操作字符串不用字符串引用就直接操作字符串
StringBuilder 类与 StringBuffer 类的相同点
方法 | 说明 |
---|---|
StringBuffer append(参数) | 追加内容到当前 StringBuffer 对象的末尾,类似于字符串的连接 |
StringBuffer deleteCharAt(int index) | 删除指定位置的字符,然后将剩余的内容形成新的字符串 |
StringBuffer insert(位置, 参数) | 在 StringBuffer 对象中插入内容,然后形成新的字符串 |
StringBuffer reverse() | 将 StringBuffer 对象中的内容反转,然后形成新的字符串 |
void setCharAt(int index, char ch) | 修改对象中索引值为 index 位置的字符为新的字符 ch |
void trimToSize() | 将 StringBuffer 对象的中存储空间缩小到和字符串长度一样的长度,减少空间的浪费,和 String 的 trim() 是一样的作用 |
StringBuffer delete(int start, int end) | 删除指定区域的字符串 |
StringBuffer replace(int start, int end, String s) | 用新的字符串替换指定区域的字符串 |
void setlength(int n) | 设置字符串缓冲区大小 |
int capacity() | 获取字符串的容量 |
void ensureCapacity(int n) | 确保容量至少等于指定的最小值。如果当前容量小于该参数,然后分配一个新的内部数组容量更大。新的容量是较大的 |
getChars(int start,int end,char chars[],int charStart); | 将字符串的子字符串复制给数组 |
StringBuilder 类与 StringBuffer 类常用方法测试代码
- public class Test {
- public static void main(String[] args) {
- Test test = new Test();
- StringBuffer strbf = new StringBuffer("Hello Swen");
- StringBuilder strbl = new StringBuilder(30);
- System.out.println("testStringBuffer 如下:");
- test.testStringBuffer(strbf);
- System.out.println("testStringBuilder 如下:");
- test.testStringBuilder(strbl);
- }
- /*
- * StringBuffer 类测试方法
- */
- public void testStringBuffer(StringBuffer str){
- // 增加字符串内容的方法
- //append(参数), 追加内容到当前对象的末尾
- str.append("你要加油学习!");
- System.out.println("追加内容到当前对象的末尾:"+str);
- // insert(位置, 参数), 在对象中插入内容
- str.insert(10,',');
- System.out.println("在对象中插入内容:"+str);
- // 操作字符串内容的方法
- //delete(int start, int end), 删除指定区域的字符串
- str.delete(10, 18);
- System.out.println("删除指定区域的字符串:"+str);
- //deleteCharAt(int index), 删除指定位置的字符
- str.deleteCharAt(10);
- System.out.println("删除指定位置的字符:"+str);
- //setCharAt(int index, char newChar), 修改对象中索引值为 index 位置的字符为新的字符 ch
- str.setCharAt(5, '-');
- System.out.println("修改对象中索引值为 index 位置的字符为新的字符 ch:"+str);
- //replace(int start, int end, String s), 用新的字符串替换指定区域的字符串
- str.replace(6, 10, "world");
- System.out.println("用新的字符串替换指定区域的字符串:"+str);
- // reverse()内容反转
- str.reverse();
- System.out.println("内容反转:"+str);
- // 将字符串的子字符串复制给数组.
- char[] ch = new char[5];
- str.getChars(0, 3, ch, 0);
- System.out.println("将字符串的子字符串复制给数组:"+Arrays.toString(ch));
- }
- /*
- * StringBuilder 类测试方法
- */
- public void testStringBuilder(StringBuilder str){
- str.append("Hello Swen");
- System.out.println("追加内容到当前对象的末尾:"+str);
- //length(), 获取字符串长度
- System.out.println("字符串长度为:"+str.length());
- //capacity(), 获取字符串的容量
- System.out.println("字符串容量为:"+str.capacity());
- // 有关字符串空间的方法
- //setLength(int newSize), 设置字符串缓冲区大小
- str.setLength(20);
- System.out.println("setLength 后, 字符串长度为:"+str.length());
- System.out.println("setLength 后, 字符串容量为:"+str.capacity());
- //trimToSize(), 存储空间缩小到和字符串长度一样的长度
- str.trimToSize();
- System.out.println("trimToSize 后, 字符串长度为:"+str.length());
- System.out.println("trimToSize 后, 字符串容量为:"+str.capacity());
- }
- }
StringBuilder 类与 StringBuffer 类常用方法测试结果
testStringBuffer 如下:
追加内容到当前对象的末尾: Hello Swen 你要加油学习!
在对象中插入内容: Hello Swen, 你要加油学习!
删除指定区域的字符串: Hello Swen!
删除指定位置的字符: Hello Swen
修改对象中索引值为 index 位置的字符为新的字符 ch:Hello-Swen
用新的字符串替换指定区域的字符串: Hello-world
内容反转: dlrow-olleH
将字符串的子字符串复制给数组:[d, l, r, , ]
testStringBuilder 如下:
追加内容到当前对象的末尾: Hello Swen
字符串长度为: 10
字符串容量为: 30
setLength 后, 字符串长度为: 20
setLength 后, 字符串容量为: 30
trimToSize 后, 字符串长度为: 20
trimToSize 后, 字符串容量为: 20
java 学习资料分享: 关注公众号 [Swen 学 java] 即可免费领取详情见 java 学习资源汇总
java 学习资源框架. PNG
来源: http://www.jianshu.com/p/a91cc3198952