String,StringBuffer与StringBuilder
关于字符串的这三个类,在使用中频繁地接触到,现在对它们做一个总结。这三个类实现了接口CharSequence,而StringBuffer和StringBuilder还同时继承于AbstractStringBuilder这个父类。
Java里的String类具体用法不具体说,现在主要讲一下String需要注意的一些问题。字符串常量池是String里的一个重要机制,通过字符串常量池,我们可以不用再为重复的字符串分配空间,有效地节省了资源。但是,如果不了解这个机制的话会导致很多的问题。例如:
String A = "tajxrey"; String B = "tajxrey"; String C = new String("tajxrey"); if (A == B) System.out.println("A == B."); else System.out.println("A != B."); if (A.equals(B)) System.out.println("A equals B."); else System.out.println("A doesn't equals B."); if (A == C) System.out.println("A == C"); else System.out.println("A != C."); if(A.equals(C)) System.out.println("A equals C."); else System.out.println("A doesn't equals C.");
结果如下:
A == B. A equals B. A != C. A equals C.
由上述结果可知,当初始化时是直接将值赋给String变量A,则A就会被放入常量池中。当有相同的值被直接赋给另一String变量B时,则是将A的地址赋给了B的地址,也就是说A和B指向的是同一地址。而通过new出来的C的地址是重新分配的。虽然C的值与A的相同,但是C的地址与A的却不一样。因此,在使用“==”比较的时候会出现不等的情况。在实际比较两String变量的值是否相等时,应该采用如下方法:
if (A != null && A.length != 0 && A.equals(B)) System.out.println("A equals B.");
String类对于字符串处理的能力已经是十分的强大了,那为什么还会有StringBuffer和StringBuilder的出现?原因在于String的字符串拼接慢的令人发指。在String类相加的时候,首先会重新new一个StringBuffer进行append,然后再使用toString返回。一般来说StringBuffer和StringBuilder字符串拼接的速度是String万倍左右。
StringBuffer和StringBuilder有太多相似之处,所以放在一起讲。相似的地方不说,StringBuffer与StringBuilder最大的不同在于StringBuffer线程安全,StringBuilder不安全。StringBuffer与StringBuilder相比拼接时间略慢,但是由于它是线程安全的,因此在多线程的时候使用的是StringBuffer。而StringBuilder只能在单线程的时候使用。引入programus的示例代码:
import java.util.Random; public class Test { public static int demo(final Object stringJoiner, final int testCount) throws InterruptedException { ThreadGroup group = new ThreadGroup(stringJoiner.getClass().getName() + "@" + stringJoiner.hashCode()); final Random rand = new Random(); Runnable listAppender = new Runnable() { public void run() { try { Thread.sleep(rand.nextInt(2)); } catch (InterruptedException e) { return; } if (stringJoiner instanceof StringBuffer) { ((StringBuffer)stringJoiner).append("0"); } else if (stringJoiner instanceof StringBuilder) { ((StringBuilder)stringJoiner).append("0"); } } }; for (int i = 0; i < testCount; i++) { new Thread(group, listAppender, "InsertList-" + i).start(); } while (group.activeCount() > 0) { Thread.sleep(10); } return stringJoiner.toString().length(); } public static void main(String[] args) throws InterruptedException { StringBuilder stringBuilder = new StringBuilder(); StringBuffer stringBuffer = new StringBuffer(); final int N = 10000; for (int i = 0; i < 10; i++) { stringBuilder.delete(0, stringBuilder.length()); stringBuffer.delete(0, stringBuffer.length()); int builderLength = demo(stringBuilder, N); int bufferLength = demo(stringBuffer, N); System.out.println("StringBuilder/StringBuffer: " + builderLength + "/" + bufferLength); } } }
运行结果:
StringBuilder/StringBuffer: 9903/10000 StringBuilder/StringBuffer: 9930/10000 StringBuilder/StringBuffer: 9908/10000 StringBuilder/StringBuffer: 9944/10000 StringBuilder/StringBuffer: 9924/10000 StringBuilder/StringBuffer: 9910/10000 StringBuilder/StringBuffer: 9916/10000 StringBuilder/StringBuffer: 9926/10000 StringBuilder/StringBuffer: 9929/10000 StringBuilder/StringBuffer: 9916/10000
由上可知,StringBuilder由于线程不安全导致了一部分操作“丢失”。