前言

本文篇幅較長,但都是滿滿的乾貨,請大家耐心觀看,相信會有不小的收穫。本人在總結的過程中也收穫了很多的知識,也希望大家可以一起借鑑學習下,希望大家最後都能有所收穫!

再言

字串的分類在java。lang包中,定義了兩個大類來表示字串: String和 String Buffer(StringBuild)類,它封裝了字串的資料結構,並定義了許多方法來處理字串。Java將字串分為兩類的目的是為了提高系統對字串的處理效率:

1。在程式執行中值不會改變的字串,用 String類來儲存和維護;

如果能夠確信程式中使用的字串的值在執行過程中不會改變,應儘量使用 String類物件;

2。在程式執行中值會改變的字串,也稱為帶字元緩衝區的字串,用 StringBuffer(StringBuild)類來儲存和維護。

如果使用的字串值在程式執行過程中會改變,就要使用 StringBuffer(StringBuild)類個物件,這樣可以提高程式的執行效能。

【注意】

Java提供的 String和 StringBuffer(StringBuild)類都定義為 final,意思是不能用它們派生出子類,這樣做的目的是為了對字串的操作進行最佳化。

String

String類用於儲存和維護值不變的字串物件,String類的定義原型如下:

//String定義原型public final class java。lang。String extends java。lang。Object { }

我們可以清楚的看出來,String該類的父類是一個Object類,由final進行修飾,表明不能產生子類(如導言所說),並且是一種工具類(由public修飾)。

瞭解了String原型,還可以看一下String原始碼:

//String部分原始碼public final class String implements java。io。Serializable, Comparable, CharSequence{ /** 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; /** Cache the hash code for the string */ private int hash; // Default to 0 /** use serialVersionUID from JDK 1。0。2 for interoperability */ private static final long serialVersionUID = -6849794470754667710L; ……。。}

從上面的原始碼中可以看出來幾點:

1)String類是final類並且它的成員方法也都預設為final方法,意味著String類和其中的方法都不可以被繼承。

注:

在Java中,被final修飾的類是不允許被繼承的,並且該類中的成員方法都預設為final方法。

2)上面列舉出了String類中的部分成員屬性,從上面可以看出String類其實是透過char陣列來儲存字串的。也可以說char是String的根本屬性。

建立String字串

一文帶你瞭解Java字串處理(String,StringBuffer,StringBuild)

建立String字串可以分為兩種情況:

(1)使用 “” 引號建立字串;

(2)使用new關鍵字建立字串。

方法一

這個方法中使用“”建立字串比較的簡單:String 變數名=“你自己需要定義的值”;

方法二

在這個方法中的建立方式就會有很多種——String和其他類一樣,可以用new運算子,並且呼叫該類的建構函式建立這種型別的物件。String類的建構函式具有以下11種格式:

public String ()

public String(String value)

public String (char value[])

public String(char value[], int offset, int count)

public String(byte ascii[], int hibyte, int offset, int count)

public String(byte ascii[], int hibyte)

public string(byte bytes[], int offset, int length, String enc)

public string(byte bytes[],String enc)

public String(byte bytes [], int offset, int length)

public String(byte bytes[])

public String (StringBuffer buffer)

建構函式各個引數的含義可以自己參閱有關的手冊,這裡就對幾個經常使用的建構函式進行解析:

public String ()

不帶引數的建構函式,採用該建構函式建立一個不含字元的空物件。eg:

String str=new String();

public String(String value)

採用引數value物件的值構造一起新的String物件。eg:

String str1=“YYH”;

String str2=new String(“YYH”);

System。out。println(str2); //顯然str2物件的內容是“YYH”

System。out。println(str1==str2); //顯然是false,這是因為str1和str2不是同一個物件,儘管他們的內容相同。

public String (char value[])

採用一個字元陣列作為引數,把這個字元陣列的內容轉換為字串,並賦予新建的物件。eg:

char a[]={‘Y’,‘Y’,‘H’}; //字元陣列

String str=new String(a); //字串str的內容是“YYH”

public String(char value[], int offset, int count)

從對字元陣列value指定的起始字元下標offset開始,將字元個數為count的字元字串作為引數,建立一個新的String物件。eg:

char a[]={‘Y’,‘Y’,‘H’}; //字元陣列

String str=new String (a,1,2); //字串str的內容是“YH”

注:

若所取的字元超出字元陣列的範圍,將產生StringIndexOutOfBoundsException字串下標越界的異常。

public String(byte ascii[], int hibyte)

以 hibyte 的值作為高8位,ascii[] 的內容作為低8位,構成一個16位字元的ASCII碼,將這些字元組成新建字串物件的內容,但 hibyte的值常常取0。

由於Java的char型別變數佔16位,可表示 Unicode字符集,但在 Internet 上最常用的的還是8位表示的ASCII字符集。由於這個原因, String類提供了該建構函式,可以根據位元組陣列將每個字元的高位位元組指定成特定值來構造字串。對普通的ASCII文字來說,每個字元的高位位元組取0,而對其他字符集則應設定為非0。eg:

byte ascii[]={65,66,67,68};

String str=new String(ascii, 0);

則str串的內容是“ABCD”,因為,字元‘A’和‘B’的 ASCII A碼分別是65和66。

public String(byte ascii[], int hibyte, int offset, int count)

這種格式是前面兩種格式的結合。eg:

byte ascii[]={65,66,67,68};

String str=new String(ascii, 0,1,2);

則str串的內容是“BC”。

public String (StringBuffer buffer)

以一個動態可改變大小的 StringBuffer 物件為引數,建立一個新的String物件,兩個物件的內容相同。

【注意】除了可以透過new運算子和建構函式建立 String物件以外,還可以採用字串常量初始化一個 String類引用,相當於採用new為這個引用建立物件,並且其內客也是字精串常量。eg:

String str= “abc”; //就是方法一的建立方法

等價於下列程式段:

char data[]={‘a’,‘b’,‘c’};

String str=new String(data);

並且str的字串內容是“abc”。

字串常量池

我們知道字串的分配和其他物件分配一樣,是需要消耗高昂的時間和空間的,而且字串我們使用的非常多。JVM為了提高效能和減少記憶體的開銷,在例項化字串的時候進行了一些最佳化:使用字串常量池。每當我們建立字串常量時,JVM會首先檢查字串常量池,如果該字串已經存在常量池中,那麼就直接返回常量池中的例項引用。如果字串不存在常量池中,就會例項化該字串並且將其放到常量池中。由於String字串的不可變性我們可以十分肯定常量池中一定不存在兩個相同的字串。

Java中的常量池,實際上分為兩種形態:靜態常量池和執行時常量池。

所謂靜態常量池,即*。class檔案中的常量池,class檔案中的常量池不僅僅包含字串(數字)字面量,還包含類、方法的資訊,佔用class檔案絕大部分空間。

而執行時常量池,則是jvm虛擬機器在完成類裝載操作後,將class檔案中的常量池載入到記憶體中,並儲存在方法區中,我們常說的常量池,就是指方法區中的執行時常量池。

來看下面的程式:

String a = “YYH”;String b = “YYH”;

a、b和字面上的chenssy都是指向JVM字串常量池中的“chenssy”物件,他們指向同一個物件

String c = new String(“YYH”);

new關鍵字一定會產生一個物件YYH(注意這個YYH和上面的YYH不同),同時這個物件是儲存在堆中。所以上面應該產生了兩個物件:儲存在棧中的c和儲存堆中YYH。但是在Java中根本就不存在兩個完全一模一樣的字串物件。故堆中的YYH應該是引用字串常量池中YYH。所以c、YYH、池YYH的關係應該是:c——->YYH——->池YYH。整個關係如下:

一文帶你瞭解Java字串處理(String,StringBuffer,StringBuild)

透過上面的圖我們可以非常清晰的認識他們之間的關係。所以我們修改記憶體中的值,他變化的是所有。

總結:

雖然a、b、c、YYH是不同的物件,但是從String的內部結構我們是可以理解上面的。String c = new String(“YYH”);雖然c的內容是建立在堆中,但是他的內部value還是指向JVM常量池的YYH的value,它構造chenssy時所用的引數依然是YYH字串常量。

String類常用的方法

(1)

charAt(int index) ** 返回指定索引處的 char 值 ,index的範圍在0到字串陣列長度減一。

(2)

compareTo(String anotherString)** 按字典順序比較兩個字串,返回負值,0和正值,分別代表小於,等於和大於

(3)

compareToIgnoreCase(String str) ** 按字典順序比較兩個字串,不考慮大小寫

(4)

concat(String str)** 將指定字串連線到此字串的結尾

(5)

contains(CharSequence s)

當且僅當此字串包含指定的 char 值序列時,返回 true

(6)

endsWith(String suffix)

測試此字串是否以指定的字尾結束

(7)

equals(String anString)

將此字串與指定的字串比較

(8)

format(String format, Object args)

使用指定的格式字串和引數返回一個格式化字串

(9)

indexOf(int ch) 與 indexOf(int ch, int fromIndex)

返回在此字串中第一次出現指定字元處的索引,沒有則返回-1,後者要從指定的索引(

fromIndex

)開始搜尋

(10)

indexOf(String str) 與 indexOf(String str, int fromIndex)

返回指定子字串在此字串中第一次出現處的索引,後者要從指定的索引開始搜尋

(11)

isEmpty() ** 當且僅當 length() 為 0 時返回 true

(12)

lastIndexOf(int ch) 與 lastIndexOf(int ch, int fromIndex)**

返回指定字元在此字串中最後一次出現處的索引,後者要從指定的索引處開始進行反向搜尋

(13)

lastIndexOf(String str) 與 lastIndexOf(String str, int fromIndex) **

返回指定子字串在此字串中最後一次出現處的索引,後者要從指定的索引開始反向搜尋

(14)

length()** 返回此字串的長度

(15)

matches(String regex)

字串是否匹配給定的正則表示式

(16)

replace(char oldChar, char newChar)

返回一個新的字串,它是透過用 newChar 替換此字串中出現的所有 oldChar 得到的

(17)

replaceAll(String regex, String replacement)

使用給定的 replacement 替換此字串所有匹配給定的正則表示式的子字串

(18)

replaceFirst(String regex, String replacement)

使用給定的 replacement 替換此字串匹配給定的正則表示式的第一個子字串

(19)

split(String regex)

根據給定正則表示式的匹配拆分此字串

(20)

startsWith(String prefix)

startsWith(String prefix, int toffset) **

測試此字串是否以指定的字首開始,後者要從指定的索引開始搜尋

(21)

char[] **

toCharArray() ** 將此字串轉換為一個新的字元陣列

(22)

toLowerCase() 與toLowerCase(Locale locale) **

將此 String 中的所有字元都轉換為小寫,前者是使用預設環境,後者是使用指定Locale的規則

(23)

toString()

返回此物件本身

(24)

toUpperCase() 與 toUpperCase(Locale locale) **

將此 String 中的所有字元都轉換為大寫,前者是使用預設環境,後者是使用指定Locale的規則

(25)

trim()** 返回一個新的字串,忽略前導空白和尾部空白

(26)

valueOf(Object)

返回引數的字串表示,其中的引數可以為各種型別 (27)

substring (int beginIndex,int endIndex) ** 提取string物件中從

beginIndex

開始到

endIndex-1**結束的字串,並返回提取的字串

下面對幾個比較常用方法進行簡單的解析:

public int length()

求陣列的長度。eg:

String str=“YYH”;

System。out。println(str。length()); //輸出 的是3

【注意】

陣列長度的例項變數length和這個字串物件求解長度不可以混淆,一個是例項變數length,還有一個是方法length(),獲得陣列長度的方法為:例項變數。length。

public boolean equals(String anString)

比較兩個字串物件的內容是否相等,相等的話返回true,不等返回false。

public boolean equalsIgnoreCase(String antherString)

忽略字母大小寫方式,比較兩個字串變數的內容是否相等

【注意】關於equals和==

(1)對於==,如果作用於基本資料型別的變數(byte,short,char,int,long,float,double,boolean ),則直接比較其儲存的“值”是否相等;如果作用於引用型別的變數(String),則比較的是所指向的物件的地址(即是否指向同一個物件)。

(2)equals方法是基類Object中的方法,因此對於所有的繼承於Object的類都會有該方法。在Object類中,equals方法是用來比較兩個物件的引用是否相等,即是否指向同一個物件。

(3)對於equals方法,注意:equals方法不能作用於基本資料型別的變數。如果沒有對equals方法進行重寫,則比較的是引用型別的變數所指向的物件的地址;而String類對equals方法進行了重寫,用來比較指向的字串物件所儲存的字串是否相等。其他的一些類諸如Double,Date,Integer等,都對equals方法進行了重寫用來比較指向的物件所儲存的內容是否相等。

/** * 關於equals和== */

public void test12(){ String s1=“hello”; String s2=“hello”; String s3=new String(“hello”); System。out。println(“===========test12============”); System。out。println( s1 == s2);

//true,表示s1和s2指向同一物件,它們都指向常量池中的“hello”物件 //flase,表示s1和s3的地址不同,即它們分別指向的是不同的物件,s1指向常量池中的地址,s3指向堆中的地址 System。out。println( s1 == s3); System。out。println( s1。equals(s3)); //true,表示s1和s3所指向物件的內容相同}

一文帶你瞭解Java字串處理(String,StringBuffer,StringBuild)

public String conc****at(String str)

將引數物件連線到呼叫物件的後面,返回連線後的新串。eg:

String s1=“hello”,s2=“YYH”,s3;

s3=s1。concat(s2);

System。out。println(s3); //輸出 的是“helloYYH”,但是s1和s2沒有發生變化

【注意】如果引數str為空(null),則concat()方法不會建立新串,而僅僅返回當前串。

字串還可以使用+號連線:eg:

public class Test { public static void main(String[] args) { String a = “——”; String b = “——”; String c = “Y” + “Y ” + a + “H” + “H” + b; System。out。println(c); } }

OUTPUT:YY ——HH——

【注意】****String c = "Y" + "Y " + a + "H" + "H" + b; 實質上的實現過程是: String c = new StringBuilder("YY").append(a).append("H").append("H").append(b).toString();

由此得出結論:當使用+進行多個字串連線時,實際上是產生了一個StringBuilder物件和一個String物件。

public String replace(char oldChar ,char newChar)

返回一個新的字串,它是透過用 newChar 替換此字串中出現的所有 oldChar 得到的 。eg:

String path=“D:/YYHjava/documents”;

System。out。println(path。replace(‘/’,‘\\’)); //輸出D:\YYHjava\documents

【注意】

‘\’代表‘’,他是一個跳脫字元

public String toString()

該方法返回當前字串物件本身。由於 String類是 Object類的子類,在 Object類中,定義了 tostring())方法,所以這裡的 tostring()實際上是對 Object類中 tostring()方法的過載。事實上,很多 Object類的子類都過載了該方法。 Object類的子類的 tostring()方法都用於將該類物件轉換為相應的一個不變字串。

public static String valueOf(各種型別 f)

這個方法的用途比較廣泛,它可以將各種資料型別轉換成一個相應的字串表示,由於它是一個 static()方法,所以不需要用 String類物件呼叫,而是以類名呼叫。在 String類中,提供了該方法的多個過載版本:

public static String valueof(boolean)

public static String valueof(char)

public static String valueof(char [])

public static String valueof(char[], int, int)

public static String valueof(double)

public static String valueof(float)

public static String valueof(int)

public static String valueof(long)

public static String valueof(Object)

valueOf()方法的應用:

public class ValueOf { public static void main (String arg[]){ char a[]={‘A’,‘B’,‘C’,‘D’,‘E’,‘F’}; int i =123456; float f=3。1415926f; boolean b=false; Object o=null; System。out。println(String。valueOf(a)); //字元陣列 System。out。println(String。valueOf(a,2,3)); System。out。println(String。valueOf(i)); //int型別 System。out。println(String。valueOf(f)); //float型別 System。out。println(String。valueOf(b)); //boolean型別 System。out。println(String。valueOf(o)); //object型別 }}

OUTPUT:ABCDEFCDE1234563。1415925falsenull

StringBuffer

前面討論的 String類適用於程式中不改變字元的情況,若對字串的每次修改都創個新的 String物件,顯然不利於提高程式的效率。Java為了解決這個問題提供了與則String類同級別的StringBuffer類。 StringBuffer類物件是一個內容可以改變的字串,修改後仍然存放在原來的物件中。這樣做是為了減少由於少量字元的插入而引起的空間分配問題。許多程式設計師只使用 String類,而讓Java在幕後透過“+”運算子過載來呼叫Stringbuffer類。 StringBuffer類的原型如下:

//StringBuffer原型:public final class java。lang。StringBuffer extends java。lang。Object{ …………。。}

我們可以清楚的看出來,StringBuffer該類的父類是一個Object類,由final進行修飾,表明不能產生子類(如導言所說),並且是一種工具類(由public修飾)。

【注意】

String Buffer類物件有一塊記憶體緩衝區,字串被存放在緩衝區中,緩衝區的大小可以隨程式的需要進行調整。

緩衝區的大小稱為物件的容量。

當修改物件內容時,只要物件包含的字元個數沒有超出容量,就不會分配新的空間,而直接在原空間內進行修改。

若字元的個數超出了容量, StringBuffer物件會自動調整容量,從而話應物件的儲存要求。

建立StringBuffer類物件

建立StringBuffer類物件是透過呼叫該類的建構函式實現的,StringBuffer類的建構函式有三種格式:

1)public StringBuffer()

該方法建立的物件為一個空物件,容量最大為16個字元。eg:

StringBuffer s1=new StringBuffer();

2)public StringBuffer(int length)

建立的物件為空,容量的長度為引數length確定。

StringBuffer s2=new StringBuffer(3); //容量為3

【注意】length應大於或等於零,不可以為負數,否則會報錯

3)public StringBuffer(String str)

建立物件的內容和str一樣,容量為引數str的長度加上16。eg:

String s3=“YYH”;

StringBuffer s4=new StringBuffer(s3); //s4的容量為19,內容是“YYH”

StringBuffer類常用的方法

常用方法見下表:

StringBuffer常用方法

** 方法名稱**** 用途****append(各種型別) **將其他型別的資料轉換為一個字串,並追加到目前緩衝區中,如果有必要,緩衝區會變大。注意:該方法有多個過載版本

capacity()

返回目前分配的空間大小,即物件的緩衝區容量

ensureCapacity(int)

要求緩衝區容量不少於引數指定值

Insert(int,多種型別)

| 將指定型別的資料轉換為一個字串,插人到int引數指定的位置 |

| **length() ** | 返回字元的個數 |

| **reverse() ** | 將緩衝區中的字元逆序存放 |

|

setCharAt(int, char)

| 將指定位置上的字元修改為另一個指定的字元 |

|

setLength(int)

| 截斷或擴充套件原來的字串,如果是擴充套件,新增加的空間全部填‘\0’ |

| **toString() ** | 根據此物件生成一個新的 String物件 |

|

getChars(int ,int ,char[] ,int)

| 將物件的一段字元複製到指定的字元陣列中 |

進行簡單的解析:

下面對幾個比較常用方法進行簡單的解析:

1)public int length()

返回字串的長度。

2)public int capacity()

返回緩衝區的大小。

3)public void setLength(int newLength)

指定物件的長度,將物件的內容進行裁減。如果引數 newlength小於物件的長度,則將物件截斷;如果 newlength大於或等於物件的長度,則對新增加的部分填充空字元。

4)public void ensureCapacity(int NewCapacity)

設定物件的緩衝區的大小,若 New Capacity小於物件的容量,則新的設定將不起作用,也就是說容量只能擴大而不能縮小。

【注意】StringBuffer類物件的長度可以擴大或者縮小,但該類物件的容量只能擴大而不能縮小。

5)public void setCharAt(int index, char ch)

將引數index位置上的值轉化為ch指定的字元。eg:

StringBuffer str=new StringBuffer(“Hello,java”);

str。setCharAt(3,‘L’); //str的內容變為“HelLo,java”。

6)public StringBuffer append(多種資料型別)

這是一個用於追加字串的方法,它將其他型別的資料(如int、char型別等)新增到String Buffer物件的尾部,返回修改後的 String Buffer物件。考慮到資料型別的多樣性,Java提供了 append()方法的多個過載版本:

public StringBuffer append(boolean)

public StringBuffer append(char)

public StringBuffer append(char[])

public StringBuffer append(char[], int, int)

public StringBuffer append(double)

public StringBuffer append(float)

public StringBuffer append(int)

public StringBuffer append(long)

public StringBuffer append(Object)

public StringBuffer append(String)

上述這些方法的返回值均是更新後的 Stringbuffer物件,而不是新建的 Stringbuffer的物件。eg:

StringBuffer s1,s2=new StringBuffer();

s1=s2; //s1和s2代表一個物件

s2。append(3。14)。append(‘ ’)。append(“java”);

System。out。println(s1==s2); //輸出true

System。out。println(s1); //輸出3。14 java

【注意】****append()方法之所以能夠將其他的資料新增到StringBuffer物件的尾部,是因為他可以****自動的呼叫String類中的一個靜態的方法ValueOf(),從而將其他型別的資料暫時轉換為一個String的臨時物件****,然後將這個物件新增到StringBuffer尾部。這就是append()方法的實現技術內幕。

“+”運算子可以連線兩個String類物件,但是不能連線連個StringBuffer物件。

7)public String toString()

該方法完成了由StringBuffer物件到String物件的轉換。因為String物件具有一定的安全性(不可修改,一旦修改就返回一個新物件)。

【注意】不可以對StringBuffer物件直接賦值,例如,str=“Good”是錯誤的,如果要賦值必須用建構函式實現。

8)public StringBuffer insert(int offest,多種型別 b)

該方法是將一個 String物件、 Object物件、字元陣列和基本型別的變數(int、 float、long、char、 boolean、 double)b插入到 offset指定的位置。

一文帶你瞭解Java字串處理(String,StringBuffer,StringBuild)

StringBuild

StringBuilder也是一個可變的字串物件,他與StringBuffer不同之處就在於它是執行緒不安全的,基於這點,它的速度一般都比StringBuffer快。與StringBuffer一樣,StringBuider的主要操作也是append與insert方法。這兩個方法都能有效地將給定的資料轉換成字串,然後將該字串的字元新增或插入到字串生成器中。

String,StringBuffer,StringBuild的區別

執行速度:在這方面的快慢為

StringBuilder > StringBuffer >String

線上程安全上:

StringBuilder是執行緒不安全的,而StringBuffer是執行緒安全的

總結

字串的知識很重要需要詳細的學習一下,我認為字串的處理的知識學會我上面所有的內容就差不多夠用了。所有要說的都在上面了,哈哈哈!!!

後言

這次的文章總結的內容有點多,因為我覺得字串的操作很重要,我們需要點耐心仔細的看完,細細評味當中的各個知識點(看完必定會有很多的收穫)整理了好久才整理好 ,很不容易!!!

有喜歡學習Java的小夥伴可以關注我一下,本人也是學習Java路上的小白,但是會自己會經常總結出一些基礎並且很實用的知識點拿出來分享給大家,希望在學習的道路上可以對你們有所幫助,我們可以一起學習一起進步。還有也歡迎大佬們和我討論關於Java的一些知識,相互學習!!!互相進步!!!

一文帶你瞭解Java字串處理(String,StringBuffer,StringBuild)