Class About String In Package Of Java Lang
這篇筆記主要用於分析Java中String系列的源代碼。以下是String系列的的類層次結構圖。這篇博文主要目的在於分析String系列源碼思想、以及String系列類型之間的關係,以及性能等。
第一序 String類型源碼解析
String類型是一個final類型,是不允許繼承一改變的。
1.持有成員變量
一直疑惑String字符串類型爲什麼那麼類似於字符數組char[ ],分析源碼後將會發現,本質就是字符數組。String類型持有私有訪問權限的字符數組。
源碼:privatefinal char value[];
都發現String中的字符串是連續不可變的,也正說明該value[ ]數組是final類型。同事Java程序中將類似於“abc”這樣的字符串編譯爲String類型的實例對象,至於這個實現細節有待於進一步學習!
同時String類型實現了Serializable序列化標記接口,所以擁有序列化ID。
源碼:privatestaticfinallongserialVersionUID= -6849794470754667710L;
String類型持有一個整形,作爲hash值。
源碼:private int hash;
2.實例構造器
a.無參構造器
publicString() {
this.value= new char[0];
}
b.字符數組作爲入參構造器
publicString(charvalue[]) {
this.value= Arrays.copyOf(value,value.length);
}
c.”abc”這樣的字符串作爲入參構造器
publicString(Stringoriginal) {
this.value= original.value;
this.hash= original.hash;
}
d.整形數組作爲入參構造器
publicString(int[]codePoints,int offset,int count) {
if (offset< 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count< 0) {
throw new StringIndexOutOfBoundsException(count);
}
// Note: offset or count might be near -1>>>1.
if (offset> codePoints.length- count) {
throw new StringIndexOutOfBoundsException(offset+ count);
}
final int end =offset + count;
// Pass 1: Compute precise size of char[]
int n =count;
for (inti =offset;i <end;i++) {
int c =codePoints[i];
if (Character.isBmpCodePoint(c))
continue;
else if (Character.isValidCodePoint(c))
n++;
else throw new IllegalArgumentException(Integer.toString(c));
}
// Pass 2: Allocate and fill in char[]
final char[]v =new char[n];
for (inti =offset,j = 0;i <end;i++,j++) {
int c =codePoints[i];
if (Character.isBmpCodePoint(c))
v[j] = (char)c;
else
Character.toSurrogates(c,v,j++);
}
this.value= v;
}
經過我自己的測試後發現:BmpCodePoint代碼點是65535是2的16次方,剛好是兩個字節(即一個字)的大小。在超出兩個字節後只能算是有效的代碼點,並非是BmpCodePoint代碼點。從代碼中也可看出,BmpCodePoint代碼點的整數是可以直接強轉成char類型的。在java中char類型剛好佔2個字節,在2個字節以內的整數都可以直接強轉換成char類型!
這裏需要了解Unicode字符的原理,以及代碼點的概念!
e.字節數組作爲入參構造器
publicString(bytebytes[],int offset,int length, StringcharsetName)
throws UnsupportedEncodingException {
if (charsetName== null)
throw new NullPointerException("charsetName");
checkBounds(bytes,offset,length);
this.value= StringCoding.decode(charsetName,bytes,offset,length);
}
f.StringBuffer作爲入參構造器
g.StringBuilder作爲入參構造器
3.成員方法
getChars( int srcBegin,int srcEnd,char dst[],int dstBegin)源碼:
publicvoid getChars(intsrcBegin,int srcEnd,char dst[],int dstBegin) {
if (srcBegin< 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd> value.length) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin> srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd- srcBegin);
}
System.arraycopy(value,srcBegin,dst,dstBegin,srcEnd - srcBegin);
}
其中調用了System類的本地方法arraycopy( ),判斷是否數組越界:開始位置是否大於0,結束位置是否大於字符串長度,開始位置是否小於0。然後子調用本地方法從開始位置到結束位置將字符串複製到目的字符串中。
String的equals( )方法被重寫,首先判斷兩個String對象是否相等,如果不等再判斷兩個String對象的字符是否相等。
indexOf(int ch, int fromIndex)源碼:
publicint indexOf(intch,int fromIndex) {
final int max =value.length;
if (fromIndex< 0) {
fromIndex = 0;
} else if (fromIndex>= max) {
// Note: fromIndex might be near -1>>>1.
return -1;
}
if (ch< Character.MIN_SUPPLEMENTARY_CODE_POINT) {
// handle most cases here (ch is a BMP code point or a
// negative value (invalid code point))
final char[]value = this.value;
for (inti =fromIndex;i <max;i++) {
if (value[i] == ch) {
return i;
}
}
return -1;
} else {
return indexOfSupplementary(ch,fromIndex);
}
}
ch< Character.MIN_SUPPLEMENTARY_CODE_POINT 這個條件非常重要,是分界BmpCode的界限。Character.MIN_SUPPLEMENTARY_CODE_POINT是java中的16進制的表示方式,以0x開頭代表十六進制,0開頭的是八進制。
Character.MIN_SUPPLEMENTARY_CODE_POINT這個數代表十進制中62355,剛好是2個字節。
非BmpCode代碼點是ValidCodePoint代碼點的索引位置方法indexOfSupplementary(intch,intfromIndex)
源碼:private int indexOfSupplementary(intch,int fromIndex) {
if (Character.isValidCodePoint(ch)) {
final char[]value = this.value;
final char hi = Character.highSurrogate(ch);
final char lo = Character.lowSurrogate(ch);
final int max =value.length- 1;
for (inti =fromIndex;i <max;i++) {
if (value[i] == hi &&value[i+ 1] ==lo) {
return i;
}
}
}
return -1;
}
int類型在java中佔4個字節,非BmpCode代碼點是ValidCodePoint代碼點是有高兩位和低兩位,這種類型的int轉化爲字符時分開來處理,作爲兩個字符
String的intern( )方法分析:
這個方法是本地方法,原理是:String的intern()方法的原理,在調用此方法時候會初始化一個空的字符串池,然後將該字符串對象加入該池中,當再次調用這個方法的時候,會判斷這個池中是否包含字符串,如果包含則從池中返回這個字符串,否則加入這個字符串並返回這個字符串對象的引用。
測試代碼和輸出結果是:
publicstaticvoid testIntern(){
System.out.println("\n測試字符串轉的本地方法intern()的原理:");
String str =new String("abc");
String str0 =str.intern();
System.out.println(str == str0);
String str1=str.intern();
System.out.println(str0 == str1);
String str2 =new String("abc");
String str3 =str2.intern();
System.out.println(str0 == str3);
System.out.println("測試字符串轉的本地方法intern()的原理結束\n");
}
測試字符串轉的本地方法intern()的原理:
false
true
true
測試字符串轉的本地方法intern()的原理結束