字符串廣泛應用 在 Java 編程中,在 Java 中字符串屬於對象,Java 提供了 String 類來創建和操作字符串。 String
類是不可改變的,所以一旦創建了 String 對象,那它的值就無法改變了。 如果需要對字符串做很多修改,那麼應該選擇使用
StringBuffer & StringBuilder 類
爲什麼String類是不可改變的?
String s = "AAAA";
System.out.println("s = " + s);
s = "BBBB";
System.out.println("s = " + s);
輸出結果:
AAAA
BBBB
從結果上看是改變了,但爲什麼說String對象是不可變的呢?
原因在於實例中的 s 只是一個 String 對象的引用,並不是對象本身,當執行 s = “BBBB”; 創建了一個新的對象 “BBBB”,而原來的 “AAAA” 還存在於內存中。
如圖:
或者根據 jdk 的源碼來分析。
字符串實際上就是一個 char 數組,並且內部就是封裝了一個 char 數組。
並且這裏 char 數組是被 final 修飾的:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
並且 String 中的所有的方法,都是對於 char 數組的改變,只要是對它的改變,方法內部都是返回一個新的 String 實例。
Java:String、StringBuffer 和 StringBuilder 的區別
String:字符串常量,字符串長度不可變。Java中String 是immutable(不可變)的。用於存放字符的數組被聲明爲final的,因此只能賦值一次,不可再更改。
StringBuffer:字符串變量(Synchronized,即線程安全)。如果要頻繁對字符串內容進行修改,出於效率考慮最好使用 StringBuffer,如果想轉成 String 類型,可以調用 StringBuffer 的 toString() 方法。Java.lang.StringBuffer 線程安全的可變字符序列。在任意時間點上它都包含某種特定的字符序列,但通過某些方法調用可以改變該序列的長度和內容。可將字符串緩衝區安全地用於多個線程。
StringBuilder:字符串變量(非線程安全)。在內部 StringBuilder 對象被當作是一個包含字符序列的變長數組。
基本原則:
- 如果要操作少量的數據用 String ;
- 單線程操作大量數據用StringBuilder ;
- 多線程操作大量數據,用StringBuffer。
String類支持的方法:
-
獲取字符串長度 用於獲取有關對象的信息的方法稱爲訪問器方法。
- String 類的一個訪問器方法是 length() 方法
- 1、length() 方法是針對字符串來說的,要求一個字符串的長度就要用到它的length()方法;
- 2、length 屬性是針對 Java 中的數組來說的,要求數組的長度可以用其 length 屬性;
- 3、Java 中的 size() 方法是針對泛型集合說的, 如果想看這個泛型有多少個元素, 就調用此方法來查看!
- String 類的一個訪問器方法是 length() 方法
-
連接字符串
-
concat() 方法
-
'+'操作符
-
String a = "a"; String b = "b"; String c = a + b;
相當於:
String c = new StringBuffer().append(a).append(b).toString();
對於字符串的加運算,當編譯成 class 文件時,會自動編譯爲 StringBuffer 來進行字符串的連接操作。
同時對於字符串常量池:
當一個字符串是一個字面量時,它會被放到一個常量池中,等待複用。
String a = "saff"; String b = "saff"; String c = new String("saff"); System.out.println(a.equal(b)); // true System.out.println(a.equal(c)); // true
這個就是字符串的常量池。
-
-
-
創建格式化字符串
- String 類的靜態方法 format() 能用來創建可複用的格式化字符串,而不僅僅是用於一次打印輸出。
-
返回指定索引處的 char 值
- charAt() 方法用於返回指定索引處的字符。索引範圍爲從 0 到 length() - 1。
-
字符串與對象進行比較、按字典順序比較兩個字符串
-
int compareTo(Object o)
-
compareTo(String anotherString)
-
關於這個方法,不管參數是對象還是字符串,最終要比較的都是兩個字符串的不同,以下稱調用方法那邊的爲原字符串,方法參數裏的爲參數字符串。
這個方法分爲兩種比較方式:
1、不同的字符在較短字符串長度之內時
2、不同的字符在較短字符串長度之外時
-
看下 compareTo 的源碼:
/* *如果參數字符串等於此字符串,則返回值 0; *如果此字符串按字典順序小於字符串參數,則*返回一個小於 0 的值; *如果此字符串按字典順序大於字符串參數,則返回一個大於 0 的值。 */ public int compareTo(String anotherString) { int len1 = value.length; int len2 = anotherString.value.length; //取數組長度裏面最小的 int lim = Math.min(len1, len2); // 獲得兩個數組,這兩個數組就是string的屬性 char v1[] = value; char v2[] = anotherString.value; int k = 0; while (k < lim) { //獲取第K的字符,進行比較 char c1 = v1[k]; char c2 = v2[k]; if (c1 != c2) { //Java使用的是Unicode編碼,因此返回這兩個字符的Unicode差值。 return c1 - c2; } k++; } //如果前lim個字符都相同,那麼就返回長度差。 return len1 - len2; }
- 1、取得string的value數組
- 2、取得value數組裏面的元素
- 3、按照unicode值進行比較
- 4、返回比較的值
String a = "a"; String b = "b"; System.out.println(a.compareTo(b));
輸出值 -1。
String a = "b"; String b = "a"; System.out.println(a.compareTo(b));
輸出值 1。
String a = "a"; String b = "a"; System.out.println(a.compareTo(b));
輸出 0。
兩個字符串首字母不同,則該方法返回首字母的 asc 碼的差值。
String a = "abc"; String b = "bcdfg"; System.out.println(a.compareTo(b));
輸出 -1。
參與比較的兩個字符串如果首字符相同,則比較下一個字符,直到有不同的爲止,返回該不同的字符的 ascii 碼差值。
String a = "abc"; String b = "abedfg"; System.out.println(a.compareTo(b));
輸出 -2。
兩個字符串不一樣長,可以參與比較的字符又完全一樣,則返回兩個字符串的長度差值。
String a = "abc"; String b = "abcdefg"; System.out.println(a.compareTo(b));
輸出 -4。
string a = "abcde"; String b = "abcd"; System.out.println(a.compareTo(b));
輸出 1。
目前 compareTo 項目中的用途是比較版本號的高低。
String a = "1.0.0"; String b = "1.0.1"; System.out.println(a.compareTo(b));
輸出 -1。
-
-
-
-
按字典順序比較兩個字符串,不考慮大小寫
-
compareToIgnoreCase()
-
關於這個方法,不管參數是對象還是字符串,最終要比較的都是兩個字符串的不同,以下稱調用方法那邊的爲原字符串,方法參數裏的爲參數字符串。
這個方法分爲兩種比較方式:
1、不同的字符在較短字符串長度之內時
返回值=原字符串與參數字符串中第一個不同字符相差的ASCII碼值,爲原減參。
例子如下:
String str1="javDscrspt"; String str2="jAvascript"; str1.compareToIgnoreCase(str2);
此時返回值爲3,是d的ASCII碼(100)減去了a的ASCII碼值(97)得到或者D與A相差得到的。
注意:只比較第一個不同(這個方法裏不考慮字母大小寫)的字符,後面的s和i也不一樣但不會進行比較了,無關字母大小寫所以只比較相同格式下相差的ASCII碼值。
2、不同的字符在較短字符串長度之外時
返回=原字符串與參數字符串相差的字符個數,原字符串長度大時爲正,反之爲負。
例子如下:
String str1="javAScript"; String str2="JaVa"; str1.compareToIgnoreCase(str2);
此時返回值爲6,是str1相比str2多出來的字符個數。
注意:此時只比較位數,而無關ASCII碼值,並非是S(s)的ASCII碼值減去0的ASCII碼值,在參數字符串前面字符和原字符串一樣時,返回值就是兩者相差的字符個數,即使改變後面的字符也不會影響到返回的值,比如String str1=“jAva233666”,此時結果仍是6。
-
-
-
當且僅當字符串與指定的StringBuffer有相同順序的字符時候返回真
- boolean contentEquals(StringBuffer sb)
-
返回指定數組中表示該字符序列的 String
- static String copyValueOf(char[] data)
- static String copyValueOf(char[] data, int offset, int count)
-
測試此字符串是否以指定的後綴結束
- boolean endsWith(String suffix)
-
將字符串與指定的對象比較,不考慮大小寫
- boolean equalsIgnoreCase(String anotherString)
-
使用平臺的默認字符集將此 String 編碼爲 byte 序列,並將結果存儲到一個新的 byte 數組中
-
byte[] getBytes()
-
可用如下方法查看字符串用 getBytes() 方法處理後返回的 byte[] 數組中的內容:
class Main { public static void main(String[] args) { String str = "make a fortune"; byte[] byt = str.getBytes(); for (byte b : byt) { System.out.println(b); } } }
以上程序運行結果爲:
109 97 107 101 32 97 32 102 111 114 116 117 110 101
可見 byte[] 數組中存放的是字符串響應位置對應的字母的哈希值,如字符串中的字母 a 對應 byte[] 數組中的 97 。
另外:返回的 byte[] 數組的長度,與原字符串的長度相等
-
-
-
使用指定的字符集將此 String 編碼爲 byte 序列,並將結果存儲到一個新的 byte 數組中
- byte[] getBytes(String charsetName)
-
將字符從此字符串複製到目標字符數組
- void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
-
返回此字符串的哈希碼
- int hashCode()
-
返回指定字符在此字符串中第一次出現處的索引
- int indexOf()
-
返回字符串對象的規範化表示形式
-
String intern()
-
儘管在輸出中調用intern方法並沒有什麼效果,但是實際上後臺這個方法會做一系列的動作和操作。在調用”ab”.intern()方法的時候會返回”ab”,但是這個方法會首先檢查字符串池中是否有”ab”這個字符串,如果存在則返回這個字符串的引用,否則就將這個字符串添加到字符串池中,然會返回這個字符串的引用。
可以看下面一個範例:
String str1 = "a"; String str2 = "b"; String str3 = "ab"; String str4 = str1 + str2; String str5 = new String("ab"); System.out.println(str5.equals(str3)); System.out.println(str5 == str3); System.out.println(str5.intern() == str3); System.out.println(str5.intern() == str4);
得到的結果:
true false true false
爲什麼會得到這樣的一個結果呢?我們一步一步的分析。
- 第一、str5.equals(str3)這個結果爲true,不用太多的解釋,因爲字符串的值的內容相同。
- 第二、str5 == str3對比的是引用的地址是否相同,由於str5採用new String方式定義的,所以地址引用一定不相等。所以結果爲false。
- 第三、當str5調用intern的時候,會檢查字符串池中是否含有該字符串。由於之前定義的str3已經進入字符串池中,所以會得到相同的引用。
- 第四,當str4 = str1 + str2後,str4的值也爲”ab”,但是爲什麼這個結果會是false呢?先看下面代碼:
String a = new String("ab"); String b = new String("ab"); String c = "ab"; String d = "a" + "b"; String e = "b"; String f = "a" + e; System.out.println(b.intern() == a); System.out.println(b.intern() == c); System.out.println(b.intern() == d); System.out.println(b.intern() == f); System.out.println(b.intern() == a.intern());
運行結果:
false true true false true
由運行結果可以看出來,b.intern() == a和b.intern() == c可知,採用new 創建的字符串對象不進入字符串池,並且通過b.intern() == d和b.intern() == f可知,字符串相加的時候,都是靜態字符串的結果會添加到字符串池,如果其中含有變量(如f中的e)則不會進入字符串池中。但是字符串一旦進入字符串池中,就會先查找池中有無此對象。如果有此對象,則讓對象引用指向此對象。如果無此對象,則先創建此對象,再讓對象引用指向此對象。
當研究到這個地方的時候,突然想起來經常遇到的一個比較經典的Java問題,就是對比equal和的區別,當時記得老師只是說“”判斷的是“地址”,但是並沒說清楚什麼時候會有地址相等的情況。現在看來,在定義變量的時候賦值,如果賦值的是靜態的字符串,就會執行進入字符串池的操作,如果池中含有該字符串,則返回引用。
執行下面的代碼:
String a = "abc"; String b = "abc"; String c = "a" + "b" + "c"; String d = "a" + "bc"; String e = "ab" + "c"; System.out.println(a == b); System.out.println(a == c); System.out.println(a == d); System.out.println(a == e); System.out.println(c == d); System.out.println(c == e);
運行的結果:
true true true true true true
-
-
-
返回指定字符在此字符串中最後一次出現處的索引
- lastIndexOf()
-
檢測字符串是否匹配給定的正則表達式
- matches()
-
測試兩個字符串區域是否相等
- boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)
-
替換爲新字符串
- replace()
-
使用給定的 replacement 替換此字符串所有匹配給定的正則表達式的子字符串
- replaceAll()
-
使用給定的參數 replacement 替換字符串第一個匹配給定的正則表達式的子字符串
- replaceFirst()
-
根據給定正則表達式的匹配拆分此字符串
-
split()
-
. 必須得加轉義字符**\**,以下是拆分 IP 地址的實例:
public class Demo { public static void main(String args[]) { String str = "192.168.1.1"; // . 必須得加 轉義字符\\ for(String s : str.split("\\.")){ System.out.println(s); } } }
-
-
-
檢測字符串是否以指定的前綴開始
- startsWith()
-
返回一個新的字符序列,它是此序列的一個子序列
- subSequence() (返回的是String)
- substring() (返回的是實現了CharSequence接口的類,可以直接下轉爲String對象)
-
將字符串轉換爲字符數組
- toCharArray()
-
將字符串轉換爲小寫
- toLowerCase()
-
返回此對象本身
- toString()
-
將字符串小寫字符轉換爲大寫
- toUpperCase()
-
用於刪除字符串的頭尾空白符
- trim()
-
返回給定data type類型x參數的字符串表示形式
- valueOf()
System.out.println(s);
}
}
}
```
-
檢測字符串是否以指定的前綴開始
- startsWith()
-
返回一個新的字符序列,它是此序列的一個子序列
- subSequence() (返回的是String)
- substring() (返回的是實現了CharSequence接口的類,可以直接下轉爲String對象)
-
將字符串轉換爲字符數組
- toCharArray()
-
將字符串轉換爲小寫
- toLowerCase()
-
返回此對象本身
- toString()
-
將字符串小寫字符轉換爲大寫
- toUpperCase()
-
用於刪除字符串的頭尾空白符
- trim()
-
返回給定data type類型x參數的字符串表示形式
- valueOf()