JAVA源码之JDK(三)――String、StringBuffer、StrinBuilder(一)

2014-11-24 07:37:08 · 作者: · 浏览: 2
Java中,除了8种基本类型,最长用的应该就是String类了。那么我们来看看JDK中的 源码是怎么建造String、StringBuffer、StrinBuilder一系列类的。
java.lang.String
在JAVA里,String类是一个非常特殊的类,我们来看一下它是怎么来表示一个字符串的。首先来看一下它的比较重要的几个属性,源码如下:
/** The value is used for character storage. */
private final char value[];
/** The offset is the first index of the storage that is used. */
private final int offset;
/** The count is the number of characters in the String. */
private final int count;
是的,其实String是用一个char数组来储存的,offset表示char[]的起始位置。count表示字符串的长度,通过字符串的length()方法只有一行return count;就看得出来。
  这里的属性都是final的,这就是String值为什么不能被改变【可不是因为final class String的final呦】。这么做的好处是String对象可以在不同用户间共用,本身是线程安全的。
来看一个构造方法:
1 public String(String original) {
2 int size = original.count;
3 char[] originalValue = original.value;
4 char[] v;
5 if (originalValue.length > size) {
6 // 如果传入的original的存储char[]的长度大于要构造的字符串的长度,就copy original有效的那部分。
7 int off = original.offset;
8 v = Arrays.copyOfRange(originalValue, off, off+size);
9 } else {
10 // 因为传入的original的存储char[]的长度等于要构造的字符串的长度,所以无需copy
11 v = originalValue;
12 }
13 this.offset = 0;
14 this.count = size;
15 this.value = v;
16 }
  先说点题外的,笔者我第一次看到第2行的时候感到很诧异,String类的count属性不是private的吗。后来经过自己实验并反复回忆初学JAVA时老师对private的描述,private修饰的属性是只有在类的内部时才能被访问,于是恍然大悟。重新认识了private关键字,也是个收获。
  再来说这个构造方法,大概翻译了下JDK的注释。这里有两点,一是第8行的数组复制,里面是最终用的是System.arraycopy()方法,这个方法在JAVA中复制数组是最快的【这是个native方法,至于底层怎么实现就不太了解,猜测是通过内存里的地址吧】。再就是第11行的v = originalValue;,就是说,用于构造String的字符串,和构造出来的新的字符串,value属性是指向同一个char[]的【其实这也无所谓,因为String.value是final的】。
  关于字符集的构造方法这里就不说了,转换来转换去好烦。
  下面来看几个Sring类常用的方法的实现:
public boolean equals(Object anObject)
View Code
先比较hashCode,然后再遍历对比两个String的value值,没什么好说的。
public boolean startsWith(String prefix, int toffset)
View Code
也很简单,遍历字符串的value值。不过注释很有意思:-1>>>1。【-1的无符号右移1位,就是整数最大值,你懂得】
public int indexOf(String str)
View Code
我们在使用这个方法时会有一个陷阱,就是sourceString.indexOf(""),传入空字符串会返回0。
public String substring(int beginIndex, int endIndex)
View Code
很简单,构造一个新的字符串。
  总之,这些常用的方法也不过是对char[]翻来覆去的操作。但提到String类就不得不提String Pool,这是JVM为了提高效率的一个缓存机制【至于JVM的这个原理,研究层次就更深入了,我想我以后会去了解吧】。目前要搞清楚String对象什么时候会在String Pool中建立,什么时候在Heap中建立,并将引用指向哪个,这个也是非常重要的。
String Pool(字符串池)
在创建字符串时,JVM的管理有如下特点:
每当用任意方式创建一个String对象时,JVM都会String Pool中查找是否存在内容相同的字符串对象,如果不存在,则在池中创建一个字符串。
在使用new关键字或包含变量的字符串拼接时,一定会在Heap中建立这个对象,并将引用指向这个对象。【同时仍然会维护String Pool】
使用等号直接指定,或纯字符串拼接时,只会操作String Pool,如果有这个字符串则直接将引用指向,如果没有则创建后指向。
有兴趣的可以自己试试,这里列举几个例子。
public native String intern();
  最后来说intern()。这是个native方法,它的执行结果是将字符串的引用指向String Pool中的对象。这样Heap中的对象就可以被回收掉了。
java.lang.StringBuffer
  我们经常需要String的变化,但String却是不可变的,那么只好串接后生成一个新的String对象来满足变化的需求。如果频繁的进行字符串拼接就会产生出大量的对象,这样很耗性能。所以这时,轮到StringBuffer来登场了。顾名思义,这是一个字符串缓冲区,可以随意变化。StringBuffer 上的主要操作是 append 和 insert 方法。
public synchronized StringBuffer append(String str)
1 public synchronized StringBuffer append(String str) {
2 super.append(str);//父类方法如下
3 return this;
4 }