引言:
这是Java系列博客的中的第一篇文章,写这个系列博客的目的有两个一个是让自己总结一下工作学习中有关Java的一些知识,还有一个就不告诉你们了。有人知道就行了。不知道的就不知道吧。通过本篇博文,你应该清楚
1.java是如何实现String和StringBuider
2.String和StringBuilder的区别以及二者之间的应用场景
String 的实现
字符串类型是所有语言里最常用的一种数据类型。为了更加清晰的说清楚我们深入看一下Java是如何实现String的。(没有JDK源码的同学需要下载,或者留言+邮箱我可以发给你)。String的实现位于包java.lang.String。这里简单列举一下对本篇文章有用的代码:
public final class String { /** The value is used for character storage. */ private final char value[]; /** * Initializes a newly created {@code String} object so that it represents * an empty character sequence. Note that use of this constructor is * unnecessary since Strings are immutable. */ public String() { this.value = new char[0]; } /** * Initializes a newly created {@code String} object so that it represents * the same sequence of characters as the argument; in other words, the * newly created string is a copy of the argument string. Unless an * explicit copy of {@code original} is needed, use of this constructor is * unnecessary since Strings are immutable. * * @param original * A {@code String} */ public String(String original) { this.value = original.value; this.hash = original.hash; } /** * Allocates a new {@code String} so that it represents the sequence of * characters currently contained in the character array argument. The * contents of the character array are copied; subsequent modification of * the character array does not affect the newly created string. * * @param value * The initial value of the string */ public String(char value[]) { this.value = Arrays.copyOf(value, value.length); } }
可以看到,String的实现是依靠一个char类型的数组。所以在Java中String是一个不可变字符串,原因很简单,如果要改变String就需要改变String内部类型为char数组的value成员,而数组一旦new完之后就无法再更改其大小了。看一下下面这个小例子:
1 String x = "hello world"; 2 String y = x; 3 System.out.println(x.equals(y)); 4 System.out.println(x == y); 5 x = "hello china"; 6 System.out.println(y); 7 System.out.println(x == y); 8 9 String z= new String("hello world"); 10 System.out.println(y.equals(z)); 11 System.out.println(y == z);
运行上面的小例子,如果你预期的结果与运行的结果一直并且也知道原因,那么字符串String就没有问题了。
StringBuilder的实现
StringBuilder的实现类似于ArrayList的实现。想要研究其内部实现细节可以去看一下JDK源码,或者看ArrayList的是实现,二者几乎一致。这里不列举源码了。有点多。这里简单陈述一下append方法的实现原理。StringBuilder的内部有一个与String一个的char[] value。当append字符串到StringBuilder中的时候,StringBuilder会自动根据新字符串的长度来判断value是否可以存的下,如果存不下则重新申请一个更大的字符数组,然后将原来已有的字符串复制过来。
String & StringBuilder
String适用于不变的字符串,StringBuilder适用于同时变化的字符串。运行一下下面的小例子。
1 long begin = System.currentTimeMillis(); 2 String total = ""; 3 for (int i = 0; i < 10000; i++) { 4 total = total + i; 5 } 6 long end = System.currentTimeMillis(); 7 System.out.println("cost:" + (end - begin)); 8 9 10 begin = System.currentTimeMillis(); 11 StringBuilder sb = new StringBuilder(); 12 for (int i = 0; i < 10000; i++) { 13 sb.append(i); 14 } 15 end = System.currentTimeMillis(); 16 System.out.println("cost:" + (end - begin));
我的输出位
cost:281 cost:2
可以看到在字符串不断变化的时候StringBuilder的性能就体现出来了。上面的例子看懂了并且也知道原因了,那么String和StringBuilder 就没有问题了。这里还应该所以下StringBuffer,StringBuffer与StringBuilder实现的逻辑一模一样,唯一的区别在于StringBuffer是线程安全的而StringBuilder是线程不安全的。
总结
String适用于字符串固定不变的情况下(String的使用无需考虑线程是否安全因为他分配在常量池中大家所有线程共享),StringBuilder适用于字符串变化频繁的情况下,如果考虑到线程安全需要使用StringBudder。