在Java編程中, String類型使用特別頻繁。但是要發揮String的作用,需要對String源碼深入理解,才能寫出高質量的代碼。
C語言不存在字符串類型,但可用字符數組表示字符串。萬變不離其宗,String的底層是基於字符數組,並且封裝了操作字符串的一系列方法。所以,String的本質是基於字符數組。
深入理解String,需要重點掌握以下幾點:
**1、String是不可變字符串
2、所有對String的修改都會返回新String
3、==和equal的區別**
且看部分關鍵源碼
/**
*這段註釋對理解String非常重要,請仔細琢磨
* Strings are constant; their values cannot be changed after they
* are created. String buffers support mutable strings.
* Because String objects are immutable they can be shared. For example:
* <p><blockquote><pre>
* String str = "abc";
* </pre></blockquote><p>
* is equivalent to:
* <p><blockquote><pre>
* char data[] = {'a', 'b', 'c'};
* String str = new String(data);
* </pre></blockquote><p>
* */
//**final修飾String,String不可被繼承,保證不可變性**
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/**
這是一個字符數組,String的所有方法都是基於該字符數組
如何保證String字符串不可變
**-用private修飾value,使得value不可被外部訪問
-用final修飾value, 不允許value指向另一個地址
-所有String方法不改變value**
以上三個因素保證了String字符串不可變
*/
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
public String() {
this.value = new char[0];
}
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
String不可變的特性,使得String字符串可被共享:
通過共享字符串,相同的字符串,不需額外分配內存空間,減少內存開銷,也有利於GC高效運行。
//代碼片段
String str = "abc";//會在常量池創建"abc"
String sharedStr = "abc";//常量池已存在"abc",不需要重新分配內存,直接引用常量池
System.out.println(str == sharedStr);//true,引用常量池同一個字符串
所有對String的修改都會返回新String:
由於String字符串是不可變的。所有對String的修改,會給新String分配內存空間,並且將該String拷貝到新String。
//代碼片段
String str = "hi,小佳";
String str1 = "my name is ben";
String newStr = str + str1;//爲newStr重新分配內存,分別將str和str1拷貝到newStr
System.out.println(str == newStr);//false,字符串內存首地址不相同
==和equals的區別:
以下是==和equals的測試案例,務必研究一番:
/**
*** == 比較兩個字符串首地址是否相等**
*/
String str = "str是字符串首地址";//str實際存儲的是字符串內存首地址
String sameStr = str;//sameStr、str指向同一個內存地址
String diffStr = "diffStr是字符串首地址,我擁有自己的內存空間";
System.out.println(str == sameStr);//true,字符串內存首地址相同
System.out.println(str == diffStr);//false,字符串內存首地址不相同
/**
*下面是equals源碼
***equals:只要兩個字符串的內存首地址相等 或者
*字符串內容相等,equals返回true;否則,返回false。**
*
*String重寫了equals方法,且看equals源碼
*/
public boolean equals(Object anObject) {
//判斷內存首地址是否相等
if (this == anObject) {
return true;
}
//判斷字符串內容是否相等
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
//測試案例
String str = "hi,小佳";
String sameStr = "hi,小佳";
String diffStr = new String( "hi,小佳");//只要new一個String,都會給該String分配新的地址空間
System.out.println(str == diffStr);//false,字符串內存首地址不相同
System.out.println(str == sameStr);//true,字符串內存首地址相同
System.out.println(str.equals(diffStr));//true,字符串內容相等
System.out.println(str.equals(sameStr));//true,字符串內存首地址不相同
==和equals的區別總結:
給定兩個String對象 str1和str2,如果str1==str2爲true,那麼str1.equals(str2)必定爲true。
總結
String是Java的基礎,也是Java中最爲常用、最爲重要的一個類型,深入理解String,爲後續Java高級編程夯實基礎!
如果希望進一步理解String,推薦直接看源碼,建議重點閱讀這幾個函數:hashCode(String的哈希算法,值得研究), toString(String重寫了這個方法),getBytes(重點了解,此函數設計的編碼知識),subString(這個方法比較常用),split。
如果上面這些知識還滿足不了你的話,可以繼續深入學習StringBuilder,StringBuffer。需要掌握如下兩個知識點:
1. String,StringBuilder,StringBuffer區別(理解這三個類的區別,非常重要!)
2. StringBuilder,StringBuffer的應用場景