課程重點:
字符串概念
字符串的內存理解
字符串的常用方法
可變字符串的常用方法
13.1. 字符串的簡介
13.1.1. 字符串的概念
字符串, 其實是由若干個字符組成的一個有序序列。 用String來表示一個字符串。
字符串中的內容, 用雙引號括起來。 在雙引號中, 字符的數量不限制, 可以是0個, 可以是1個, 也可以是多個。
String str1 = "hello world";
13.1.2. 字符串的內存分析
字符串, 是一個引用數據類型。 但是字符串的引用, 和之前在面向對象部分的引用有一點差別。
差別: 類的對象, 是在堆上開闢的空間。 字符串, 是在 常量池 中開闢的空間。
String str = "hello world";
此時, "hello world", 是在 常量池 中開闢的空間。 str裏面存儲的, 其實是常量池中的某一個內存的地址。
當 str = "30"; 的時候, 其實, 並不是修改了 str指向的空間中的內容。 因為常量池空間特性, 一個空間一旦開闢完成了, 裏面的值是不允許修改的。 此時, 是在常量池中開闢了一塊新的空間, 存儲了 "30", 並把這個新的空間的地址給str賦值了。
字符串類型, 之所以選擇在常量池中進行空間的開闢, 而不是在堆上。 原因是需要使用 享元原則 。
// 當第一次使用到"hello world"這個字符串的時候, 常量池中並沒有這塊內存。
// 此時, 就需要去開闢一塊新的空間, 存儲為 "hello world", 並且把空間的地址賦值給了str1。
String str1 = "hello world";
// 當再次使用到 "hello world" 這個字符串的時候, 常量池中現在是有這塊空間的。
// 此時, 就不需要在開闢新的空間了, 直接將現有的這個空間地址賦值給 str2。
String str2 = "hello world";
// 即: str1 和 str2 現在都指向 "hello world"
System.out.println;
String str = new String;
String是一個Java中用來描述字符串的類, 裏面是有構造方法的。
通過String類提供的構造方法, 實例化的字符串對象, 在堆上開闢的空間。 在堆空間中, 有一個內部維護的屬性, 指向了常量池中的某一塊空間。
// 在堆上開闢了一個String對象的空間, 把這個堆上空間的地址給了str1
// 在堆空間中, 有一個內部的屬性, 指向了常量池中的 "hello world"
String str1 = new String;
// 在堆上開闢了一個String對象的空間, 把這個堆上空間的地址給了str2
// 在堆空間中, 有一個內部的屬性, 指向了常量池中的 "hello world"
String str2 = new String;
System.out.println; // false: 因為此時 str1和str2 裏面存儲的是兩塊堆空間的地址。
System.out.println); // true: 因為在String類中,已經重寫過equals方法了, 重寫的實現為比較實際指向的常量池中的字符串。
13.1.3 字符串拼接的內存分析
直接使用兩個字符串字面量進行拼接
其實, 就是直接將兩個由雙引號直接括起來的字符串進行拼接 。 類似於 String str = "hello" "world"; 。
這裏, 直接在常量池中進行空間操作。 將常量池中拼接之後的結果, 地址給 str 進行賦值。
使用一個字符串變量和其他的進行拼接
這裏的拼接, 不是在常量池中直接完成的。
在這個拼接的過程中, 隱式的實例化了一個String類的對象, 在堆上開闢了空間。 堆上空間內部維護了一個指向了常量池中拼接結果的一個屬性。 這個堆上的空間地址給左側的引用進行了賦值。
13.2. 字符串的常用方法
13.2.1. 字符串的構造方法
13.2.1.1. 字符串構造方法列舉
13.2.1.2. 示例代碼
/**
* @Description 字符串的構造方法
*/
public class StringMethod1 {
public static void main {
// 1. 無參構造, 實例化一個空的字符串對象。 所謂的空字符串,其實是 "", 並不是null。
String s1 = new String(); // String s1 = "";
System.out.println;
// 2. 通過一個字符串, 實例化另外一個字符串。
String s2 = new String;
System.out.println;
char[] arr1 = { 'h', 'e', 'l', 'l', 'o' };
// 3. 通過一個字符數組, 實例化一個字符串。將字符數組中的所有的字符拼接到一起。
String s3 = new String;
System.out.println;
// 4. 通過一個字符數組, 實例化一個字符串。 將字符數組中的指定範圍的字符拼接到一起。
String s4 = new String;
System.out.println;
byte[] arr2 = { 97, 98, 99, 100, 101, 102, 103, 104 };
// 5. 將一個字節數組中的每一個字節,轉成對應的字符,再拼接到一起,組成一個字符串。
String s5 = new String;
System.out.println;
// 6. 將一個字節數組中的offset位開始,取length個字節,將每一個字節,轉成對應的字符,再拼接到一起,組成一個字符串。
String s6 = new String;
System.out.println;
}
}
13.2.2. 字符串的非靜態方法
13.2.2.1. 前言
因為字符串, 是常量。 任何的修改字符串的操作, 都不會對所修改的字符串造成任何的影響。 所有的對字符串的修改操作, 其實都是實例化了新的字符串對象。 在這個新的字符串中, 存儲了修改之後的結果。 並將這個新的字符串以返回值的形式返回。 所以, 如果需要得到對一個字符串修改之後的結果, 需要接收方法的返回值。
13.2.2.2. 常用的非靜態方法
13.2.2.3. 示例代碼
import java.util.Arrays;
/**
* @Description 字符串常用的非靜態方法
*/
public class StringMethod2 {
public static void main {
// 1. 字符串的拼接,效率比加號拼接高
String ret1 = "hello".concat;
System.out.println; // helloworld
// 2. 字符串截取
String ret2 = "hello world".substring;
System.out.println; // lo world
String ret3 = "hello world".substring;
System.out.println; // lo wo
// *. 字符序列截取
CharSequence charSequence = "hello world".subSequence;
System.out.println;
// 3. 用新的字符替換原字符串中所有的舊的字符
String ret4 = "hello world".replace;
System.out.println; // heLLo worLd
// 4. 用新的字符序列替換原字符串中所有的舊的字符序列
String ret5 = "hello world".replace;
System.out.println; // he~o world
// 5. 轉成字符數組
char[] ret6 = "hello world".toCharArray();
System.out.println); //
// 6. 轉成字節數組
byte[] ret7 = "hello world".getBytes();
System.out.println); //
// 7. 獲取某一個字符在一個字符串中第一次出現的下標。
int ret8 = "hello world".indexOf;
System.out.println; // 2
// 8. 獲取某一個字符在一個字符串中從fromIndex位開始往後,第一次出現的下標。
int ret9 = "hello world".indexOf;
System.out.println; // 9
// 9. 獲取某一個字符在一個字符串中最後一次出現的下標。
int ret10 = "hello world".lastIndexOf;
System.out.println; // 7
// 10. 獲取某一個字符在一個字符串中,從fromIndex位開始往前,最後一次出現的下標
int ret11 = "hello world".lastIndexOf;
System.out.println; // 4
// 11. 字符串大小寫字母轉變
System.out.println);
System.out.println);
// 12. 判斷一個字符串中, 是否包含另外一個字符串。
System.out.println);
// 需求:判斷一個字符串中是否包含某一個字符
// 答案:或者這個字符在字符串中出現的下標,如果不是-1,説明包含。
// 13. 判斷一個字符串, 是否是以指定的字符串作為開頭。
System.out.println);
System.out.println);
// 14. 去除一個字符串首尾的空格
System.out.println);
// 15. 判斷兩個字符串的內容是否相同
System.out.println);
System.out.println); // true
// 16. 比較兩個字符串的大小
// > 0: 前面的字符串 > 參數字符串
// == 0: 兩個字符串大小相等
// < 0: 前面的字符串 < 參數字符串
// 比較邏輯:
// 依次比較每一位的字符的大小。
// 如果某一次的字符比較可以分出大小,本次的比較結果將作為整體的字符串的比較結果。
int result = "hello world".compareTo;
System.out.println;
}
}
13.2.3. 字符串的靜態方法
13.2.3.1. 常用的靜態方法
13.2.3.2. 示例代碼
/**
* @Description
*/
public class StringMethod3 {
public static void main {
// 將若干個字符串拼接到一起,在拼接的時候,元素與元素之間以指定的分隔符進行分隔
String str1 = String.join;
System.out.println;
float score = 100;
String name ="xiaoming";
int age = 19;
// 大家好,我叫xiaoming,今年19歲了,本次考試考了100分。
/**
* 常見佔位符:
* %s : 替代字符串 -> %ns: 湊夠n位字符串,如果不夠,補空格
* %d : 整型數字佔位符 -> %nd: 湊夠n位,如果不夠補空格。
* %f : 浮點型數字佔位符 -> %.nf: 保留小數點後面指定位的數字
* %c : 字符型佔位符
*/
String str2 = String.format;
System.out.println;
}
}
13.3. StringBuffer和StringBuilder類
13.3.1. 概念
都是用來操作字符串的類。
字符串都是常量, 所有的操作字符串的方法, 都不能直接修改字符串本身。 如果我們需要得到修改之後的結果, 需要接收返回值。
StringBuffer和StringBuilder不是字符串類, 是用來操作字符串的類。 在類中維護了一個字符串的屬性, 這些字符串操作類中的方法, 可以直接修改這個屬性的值。 對於使用方來説, 可以不去通過返回值獲取操作的結果。
在StringBuffer或者StringBuilder類中, 維護了一個字符數組。 這些類中所有的操作方法, 都是對這個字符數組進行的操作。
13.3.2. 常用方法
13.3.3. 示例代碼
/**
* @Description
*/
public class Test {
public static void main {
// 1. 構造方法
StringBuilder sb = new StringBuilder;
// 2. 增: 在一個字符串後面拼接其他的字符串
sb.append;
// 3. 增: 在指定的下標位插入一條數據
sb.insert;
// 4. 刪: 刪除字符串中的 args) {
// 需求: 進行字符串的拼接 100000 次。
String str = "";
StringBuffer buffer = new StringBuffer();
StringBuilder builder = new StringBuilder();
int times = 100000;
// String類的拼接
long time0 = System.currentTimeMillis();
for {
str = i;
}
long time1 = System.currentTimeMillis();
// StringBuffer的拼接
for {
buffer.append;
}
long time2 = System.currentTimeMillis();
for {
builder.append;
}
long time3 = System.currentTimeMillis();
System.out.println);
System.out.println);
System.out.println);
}
}