StringBuffer
StringBuffer是final类,实现了Serializable接口,可以保存到文件,或网络传输。继承了抽象类AbstractStringBuilder,StringBuffer继承了AbstractStringBuilder类的char[] value属性,用于存放字符。
所以对于Stringbuffer而言,字符串是可变的,因为保存字符串的char数组,没有被final修饰。
String和StringBuffer的对比
-
String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更新地址,效率比较低。底层实现是private final char value[];
-
StringBuffer保存的是字符串变量,里面的值可以更改,每次StringBuffer更新是更新内容,不需要更新地址,效率较高,但对于StringBuffer而言,有一个字符串长度的限制,当超过限制时,就需要通过扩容来增加长度。即便如此,也是比String运用起来方便了很多。底层实现时char value[];
在之前的博客“Java基础之:OOP——抽象类”中的最后一个案例,就体现了StringBuffer在拼接字符串上的速度远远优于String。其原理就是因为,StringBuffer底层不是final修饰的char[]数组。
测试案例
public class StringBuffer { public static void main(String[] args) { // TODO Auto-generated method stub long start = System.currentTimeMillis(); StringBuffer s = new StringBuffer(""); for (int i = 0; i < 80000; i++) { s.append("hello"); } long end = System.currentTimeMillis(); System.out.println("耗时=" + (end - start) + " length=" + s.length()); } }
由于StringBuffer中可以使用的方法大多都与String相同,所以这里不再介绍。
应用案例
输入价格,要求打印效果示例 7777123567.59=> 7,777,123,567.59 ;123,564.59 <= 123456.59
package class_StringBuffer; import java.util.Scanner; public class ClassWork01 { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String in = scanner.next(); StringBuffer sb = new StringBuffer(in); int index = sb.indexOf("."); if (index != -1) { for (int i = index - 3; i > 0; i -= 3) { //直接先减掉一个3,就定位到需要插入逗号的位置 //if (i != index) { sb.insert(i, ","); //} } } else { for (int i = 0; i < sb.length(); i += 3) { if (i != 0) { sb.insert(i, ","); } } } System.out.println(sb); } }
StringBuilder
-
StringBuilder是一个可变的字符序列。此类提供一个与StringBuffer兼容的API,但不保证同步(多线程问题,即在多个线程同时访问时出现问题)。该类被设计作为StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果不考虑线程安全问题,可以优先使用此类,在大多数情况下,它比StringBuffer要快。
-
在StringBuilder中主要使用的是append与insert方法,可重载这些方法,以接收任何类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串生成器中。append 方法始终将这些字符添加到生成器的末端;而 insert 方法则在指定的点添加字符。
StringBuffer与StringBuilder都是可变序列,所以使用方法上是一样的。
String、StringBuffer、StringBuilder的比较
-
String:不可变字符序列, 效率低,但是复用率高。
-
StringBuffer:可变字符序列、效率较高(增删)、线程安全(方法有synchronized)
-
StringBuilder(JDK1.5):可变字符序列、效率最高、线程不安全(方法没有synchronized)
-
String s = "a"; (创建了一个字符串)。String s += "b"; (再次创建字符串"ab")。实际上原来的字符串"a"已经被丢弃了,创建了一个新的字符串"ab"。如果多次执行这种修改操作,就会有大量的副本字符串对象被丢弃来内存中,降低效率。如果这种情况出现在循环语句中,会极大的影响性能。
-
结论:当需要频繁的修改字符串时,不要使用String类型声明字符串。
测试案例
public class StringVsStringBufferVsStringBuilder { public static void main(String[] args) { // TODO Auto-generated method stub String text = ""; //字符串 long startTime = 0L; long endTime = 0L; StringBuffer buffer = new StringBuffer("");//StringBuffer StringBuilder builder = new StringBuilder("");//StringBuilder startTime = System.currentTimeMillis(); for (int i = 0; i < 80000; i++) { buffer.append(String.valueOf(i)); } endTime = System.currentTimeMillis(); System.out.println("StringBuffer的执行时间:" + (endTime - startTime)); startTime = System.currentTimeMillis(); for (int i = 0; i < 80000; i++) { builder.append(String.valueOf(i)); } endTime = System.currentTimeMillis(); System.out.println("StringBuilder的执行时间:" + (endTime - startTime)); startTime = System.currentTimeMillis(); for (int i = 0; i < 80000; i++) { text = text + i; } endTime = System.currentTimeMillis(); System.out.println("String的执行时间:" + (endTime - startTime)); } }