- 🎥?個人主頁:深魚~
- 🔥收錄專欄:JavaSE
- 🌄歡迎 👍點贊?評論?收藏
目錄
前言:
一、常用方法
1.1 字符串構造
1.2 String對象的比較
(1)==比較是否引用同一個對象
注意:對于內置類型,==比較的是變量中的值;對于引用類型==比較的是引用中的地址
(2)boolean equals(Object anObject) 方法:按照字典序比較
(3)?int compareTo(String s) 方法: 按照字典序進行比較
(4)?int compareToIgnoreCase(String str) 方法:與compareTo方式相同,但是忽略大小寫比較
1.3 字符串查找
?1.4轉化
(1)數值和字符串轉化
(2)大小寫轉換
(3)字符串轉數組
(4)格式化
1.5??字符串替換
1.6?字符串拆分
1.7 字符串截取
1.8?其他操作方法
1.9?字符串的不可變性
1.10字符串修改
二、 StringBuilder和StringBuffer
2.1 StringBuilder的介紹
2.2面試題
前言:
在C語言中已經涉及到字符串了,但是在C語言中要表示字符串只能使用字符數組或者字符指針,可以使用標準庫提供的字符串系列函數完成大部分操作,但是這種將數據和操作數據方法分離開的方式不符合面相對象的思想,而字符串應用又非常廣泛,因此Java語言專門提供了String類。
在開發和校招筆試中,字符串也是常客,比如:
把字符串轉換成整數
字符串相加
而且在面試中也頻繁被問到,比如:String、StringBuff和StringBulider之間的區別等
一、常用方法
1.1 字符串構造
String類提供的構造方式非常多,常用的就以下三種:
public static void main(String[] args) {//常量字符串String s1 = "Hello World";//直接newString對象String s2 = new String("Hello World");//使用字符數組進行構造char [] array = {'H','e','l','l','o','W','o','r','l','d'};String s3 = new String(array);}
注意:
(1)String是引用類型,內部并不存儲字符串本身,在String類的實現源碼中,String類實例變量如下:
public static void main(String[] args) {// s1和s2引用的是不同對象 s1和s3引用的是同一對象String s1 = new String("hello");String s2 = new String("world");String s3 = s1;
}
?(2)?在Java中“”引起來的也是String類型對象
// 打印"hello"字符串(String對象)的長度
System.out.println("hello".length());
1.2 String對象的比較
字符串的比較是常見操作之一,比如:字符串排序。Java中總共提供了4中方式:
(1)==比較是否引用同一個對象
注意:對于內置類型,==比較的是變量中的值;對于引用類型==比較的是引用中的地址
public static void main(String[] args) {int a = 10;int b = 20;int c = 10;// 對于基本類型變量,==比較兩個變量中存儲的值是否相同System.out.println(a == b); // falseSystem.out.println(a == c); // true// 對于引用類型變量,==比較兩個引用變量引用的是否為同一個對象String s1 = new String("hello");String s2 = new String("hello");String s3 = new String("world");String s4 = s1; //s1和s4引用的是同一對象System.out.println(s1 == s2); // falseSystem.out.println(s2 == s3); // falseSystem.out.println(s1 == s4); // true}
(2)boolean equals(Object anObject) 方法:按照字典序比較
字典序:字符大小的順序
String類重寫了父類Object中equals方法,Object中equals默認按照==比較,String重寫equals方法后,按照如下規則進行比較,比如: s1.equals(s2)
public boolean equals(Object anObject) {// 1. 先檢測this 和 anObject 是否為同一個對象比較,如果是返回trueif (this == anObject) {return true;}// 2. 檢測anObject是否為String類型的對象,如果是繼續比較,否則返回falseif (anObject instanceof String) {// 將anObject向下轉型為String類型對象String anotherString = (String) anObject;int n = value.length;// 3. this和anObject兩個字符串的長度是否相同,是繼續比較,否則返回falseif (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;// 4. 按照字典序,從前往后逐個字符進行比較while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false;}
public static void main(String[] args) {String s1 = new String("hello");String s2 = new String("hello");String s3 = new String("Hello");// s1、s2、s3引用的是三個不同對象,因此==比較結果全部為falseSystem.out.println(s1 == s2); // falseSystem.out.println(s1 == s3); // false// equals比較:String對象中的逐個字符// 雖然s1與s2引用的不是同一個對象,但是兩個對象中放置的內容相同,因此輸出true// s1與s3引用的不是同一個對象,而且兩個對象中內容也不同,因此輸出falseSystem.out.println(s1.equals(s2)); // trueSystem.out.println(s1.equals(s3)); // false}
(3)?int compareTo(String s) 方法: 按照字典序進行比較
與equals不同的是,equals返回的是boolean類型,而compareTo返回的是int類型。具體比較方式:
1. 先按照字典次序大小比較,如果出現不等的字符,直接返回這兩個字符的大小差值
2. 如果前k個字符相等(k為兩個字符長度最小值),返回值兩個字符串長度差值
public static void main(String[] args) {String s1 = new String("abc");String s2 = new String("ac");String s3 = new String("abc");String s4 = new String("abcdef");System.out.println(s1.compareTo(s2)); // 不同輸出字符差值-1System.out.println(s1.compareTo(s3)); // 相同輸出 0System.out.println(s1.compareTo(s4)); // 前k個字符完全相同,輸出長度差值 -3}
(4)?int compareToIgnoreCase(String str) 方法:與compareTo方式相同,但是忽略大小寫比較
public static void main(String[] args) {String s1 = new String("abc");String s2 = new String("ac");String s3 = new String("ABc");String s4 = new String("abcdef");System.out.println(s1.compareToIgnoreCase(s2)); // 不同輸出字符差值-1System.out.println(s1.compareToIgnoreCase(s3)); // 相同輸出 0System.out.println(s1.compareToIgnoreCase(s4)); // 前k個字符完全相同,輸出長度差值 -3}
1.3 字符串查找
方法 | 功能 |
char charAt(int index) | 返回index位置上字符,如果index為負數或者越界,拋出IndexOutOfBoundsException異常 |
int indexOf(int ch) | 返回ch第一次出現的位置,沒有返回-1 |
int indexOf(int ch, int fromIndex) | 從fromIndex位置開始找ch第一次出現的位置,沒有返回-1 |
int indexOf(String str) | 返回str第一次出現的位置,沒有返回-1 |
int indexOf(String str, int fromIndex) | 從fromIndex位置開始找str第一次出現的位置,沒有返回-1 |
int lastIndexOf(int ch) | 從后往前找,返回ch第一次出現的位置,沒有返回-1 |
int lastIndexOf(int ch, int fromIndex) | 從fromIndex位置開始找,從后往前找ch第一次出現的位置,沒有返回-1 |
int lastIndexOf(String str) | 從后往前找,返回str第一次出現的位置,沒有返回-1 |
int lastIndexOf(String str, int fromIndex) | 從fromIndex位置開始找,從后往前找str第一次出現的位置,沒有返回-1 |
public static void main(String[] args) {String s = "aaabbbcccaaabbbccc";System.out.println(s.charAt(3)); // 'b'System.out.println(s.indexOf('c')); // 6System.out.println(s.indexOf('c', 10)); // 15System.out.println(s.indexOf("bbb")); // 3System.out.println(s.indexOf("bbb", 10)); // 12System.out.println(s.lastIndexOf('c')); // 17System.out.println(s.lastIndexOf('c', 10)); // 8System.out.println(s.lastIndexOf("bbb")); // 12System.out.println(s.lastIndexOf("bbb", 10)); // 3
}
?1.4轉化
(1)數值和字符串轉化
數字轉字符串:String.valueof( )
字符串轉數字:Integer.parestInt (字符串) (以轉為int類型數據為例)
class Student {public String name;public int age;public Student(String name, int age) {this.name = name;this.age = age;}public String toString() {return "name:" + name + " age:" + age;}
}
public static void main(String[] args) {// 數字轉字符串String s1 = String.valueOf(1234);String s2 = String.valueOf(12.34);String s3 = String.valueOf(true);String s4 = String.valueOf(new Student("Hanmeimei", 18));System.out.println(s1); //1234System.out.println(s2); //12.34System.out.println(s3); //trueSystem.out.println(s4); //name:Hanmeimei age:18需要重寫toString方法,否則打印就是Student@1b6d3586System.out.println("=================================");// 字符串轉數字// 注意:Integer、Double等是Java中的包裝類型,這個后面會講到int data1 = Integer.parseInt("1234");double data2 = Double.parseDouble("12.34");System.out.println(data1);Sy stem.out.println(data2);
}
(2)大小寫轉
字符串.toUpperCase()
字符串.toLowerCase()
public static void main(String[] args) {String s1 = "hello";String s2 = "HELLO";// 小寫轉大寫System.out.println(s1.toUpperCase());// 大寫轉小寫System.out.println(s2.toLowerCase());
}
(3)字符串轉數組
字符串.toCharArray( )
public static void main(String[] args) {String s = "hello";// 字符串轉數組char[] ch = s.toCharArray();for(char a : ch) { //遍歷數組這樣也可以System.out.print(a);}//for (int i = 0; i < ch.length; i++) {// System.out.print(ch[i]);//}System.out.println();// 數組轉字符串String s2 = new String(ch);System.out.println(s2);}
(4)格式化
public static void main(String[] args) {String s = String.format("%d-%d-%d", 2019, 9,14);System.out.println(s);
}
//2019-9-14
1.5??字符串替換
使用一個指定的新的字符串替換掉已有的字符串數據,可用的方法如下
方法 | 功能 |
String replaceAll(String regex, String replacement) | 替換所有的指定內容 |
String replaceFirst(String regex, String replacement) | 替換首個內容 |
代碼示例: 字符串的替換處理
String str = "helloworld" ;
System.out.println(str.replaceAll("l", "_"));
System.out.println(str.replaceFirst("l", "_"));//he__owor_d
//he_loworld
?注意事項: 由于字符串是不可變對象, 替換不修改當前字符串, 而是產生一個新的字符串.
1.6?字符串拆分
可以將一個完整的字符串按照指定的分隔符劃分為若干個子字符串。可用方法如下:
方法 | 功能 |
String[] split(String regex) | 將字符串全部拆分 |
String[] split(String regex, int limit) | 將字符串以指定的格式,拆分為limit組 |
代碼示例: 實現字符串的拆分處理
String str = "hello world hello bit" ;
String[] result = str.split(" ") ; // 按照空格拆分
for(String s: result) {
System.out.println(s);
}//hello
//world
//hello
//bit
?代碼示例: 字符串的部分拆分
String str = "hello world hello bit" ;
String[] result = str.split(" ",2) ;
for(String s: result) {
System.out.println(s);
}//hello
//world hello bit
?拆分是特別常用的操作. 一定要重點掌握. 另外有些特殊字符作為分割符可能無法正確切分, 需要加上轉義.
代碼示例: 拆分IP地址
String str = "192.168.1.1" ;
String[] result = str.split("\\.") ;
for(String s: result) {System.out.println(s);
}
?注意事項:
1. 字符‘' ." ," | "," * "," + "都得加上轉義字符,前面加上 "\\" .
2. 而如果是 "\" ,那么就得寫成 "\\\\"?
(第一個和第三個\字符轉義,轉義后是\\,這\\中前面一個也是字符轉義,實際上就一個\)
3. 如果一個字符串中有多個分隔符,可以用"|"作為連字符.
代碼示例: 多次拆分注意事項:
public static void main(String[] args) {String str = "name=zhangsan&age=18" ;String[] ret = str.split("&");for (String x: ret) {String[] s = x.split("=");for (String ss: s) {System.out.println(ss);}}}//name
//zhangsan
//age
//18
?這種代碼在以后的開發之中會經常出現
1.7 字符串截取
?從一個完整的字符串之中截取出部分內容。可用方法如下
方法 | 功能 |
String substring(int beginIndex) | 從指定索引截取到結尾 |
String substring(int beginIndex, int endIndex) | 截取部分內容 |
代碼示例: 觀察字符串截取
String str = "helloworld" ;
System.out.println(str.substring(5));
System.out.println(str.substring(0, 5));//world
//hello
?注意事項:
1. 索引從0開始
2. 注意前閉后開區間的寫法, substring(0, 5) 表示包含 0 號下標的字符, 不包含 5 號下標
(左閉右開)
1.8?其他操作方法
方法 | 功能 |
String trim() | 去掉字符串中的左右空格,保留中間空格 |
String toUpperCase() | 字符串轉大寫 |
String toLowerCase() | 字符串轉小寫 |
代碼示例: 觀察trim()方法的使用
String str = " hello world " ;
System.out.println("["+str+"]");
System.out.println("["+str.trim()+"]");//[ hello world ]
//[hello world]
?trim 會去掉字符串開頭和結尾的空白字符(空格, 換行, 制表符等).
代碼示例: 大小寫轉換
String str = " hello%$$%@#$%world 哈哈哈 " ;
System.out.println(str.toUpperCase());
System.out.println(str.toLowerCase());// HELLO%$$%@#$%WORLD 哈哈哈
// hello%$$%@#$%world 哈哈哈
?這兩個函數只轉換字母
1.9?字符串的不可變性
String是一種不可變對象. 字符串中的內容是不可改變。字符串不可被修改,是因為:
1. String類在設計時就是不可改變的,String類實現描述中已經說明了
以下來自JDK1.8中String類的部分實現
?String類中的字符實際保存在內部維護的value字符數組中,該圖還可以看出:
?1. String類被final修飾,表明該類不能被繼承
?2. value被修飾被final修飾,表明value自身的值不能改變,即不能引用其它字符數組,但是其引用空間中的內容可以修改。
2. 所有涉及到可能修改字符串內容的操作都是創建一個新對象,改變的是新對象
比如 replace 方法:
?【糾正】網上有些人說:字符串不可變是因為其內部保存字符的數組被final修飾了,因此不能改變。這種說法是錯誤的,不是因為String類自身,或者其內部value被final修飾而不能被修改。
final修飾類表明該類不想被繼承,final修飾引用類型表明該引用變量不能引用其他對象,但是其引用對象中的內容是可以修改的。
public static void main(String[] args) {final int array[] = {1,2,3,4,5};array[0] = 100;System.out.println(Arrays.toString(array));// array = new int[]{4,5,6}; // 編譯報錯:Error:(19, 9) java: 無法為最終變量array分配值
}
?為什么 String 要設計成不可變的?(不可變對象的好處是什么?) (選學)
1. 方便實現字符串對象池. 如果 String 可變, 那么對象池就需要考慮寫時拷貝的問題了.
2. 不可變對象是線程安全的.
3. 不可變對象更方便緩存 hash code, 作為 key 時可以更高效的保存到 HashMap 中
?那如果想要修改字符串中內容,該如何操作呢?
1.10字符串修改
注意:盡量避免直接對String類型對象進行修改,因為String類是不能修改的,所有的修改都會創建新對象,效率非常低下
public static void main(String[] args) {String s = "hello";s += " world";System.out.println(s); // 輸出:hello world
}
?但是這種方式不推薦使用,因為其效率非常低,中間創建了好多臨時對象
public static void main(String[] args) {long start = System.currentTimeMillis();String s = "";for(int i = 0; i < 10000; ++i){s += i;} long end = System.currentTimeMillis();System.out.println(end - start);start = System.currentTimeMillis();StringBuffer sbf = new StringBuffer("");for(int i = 0; i < 10000; ++i){sbf.append(i);} end = System.currentTimeMillis();System.out.println(end - start);start = System.currentTimeMillis();StringBuilder sbd = new StringBuilder();for(int i = 0; i < 10000; ++i){sbd.append(i);}end = System.currentTimeMillis();System.out.println(end - start);}
?可以看待在對String類進行修改時,效率是非常慢的,因此:盡量避免對String的直接需要,如果要修改建議盡量使用StringBuffer或者StringBuilder。
b. 借助StringBuffer 和 StringBuilder
二、 StringBuilder和StringBuffer
2.1 StringBuilder的介紹
由于String的不可更改特性,為了方便字符串的修改,Java中又提供StringBuilder和StringBuffer類。這兩個類大部分功能是相同的,這里介紹 StringBuilder常用的一些方法
方法 | 說明 |
StringBuff append(String str) | 在尾部追加,相當于String的+=,可以追加:boolean、char、char[]、double、float、int、long、Object、String、StringBuff的變量 |
char charAt(int index) | 獲取index位置的字符 |
int length() | 獲取字符串的長度 |
int capacity() | 獲取底層保存字符串空間總的大小 |
void ensureCapacity(int mininmumCapacity) | 擴容 |
void setCharAt(int index, char ch) | 將index位置的字符設置為ch |
int indexOf(String str) | 返回str第一次出現的位置 |
int indexOf(String str, int fromIndex) | 從fromIndex位置開始查找str第一次出現的位置 |
int lastIndexOf(String str) | 返回最后一次出現str的位置 |
int lastIndexOf(String str, int fromIndex) | 從fromIndex位置開始找str最后一次出現的位置 |
StringBuff insert(int offset, String str) | 在offset位置插入:八種基類類型 & String類型 & Object類型數據 |
StringBuffer deleteCharAt(int index) | 刪除index位置字符 |
StringBuffer delete(int start, int end) | 刪除[start, end)區間內的字符 |
StringBuffer replace(int start, int end, String str) | 將[start, end)位置的字符替換為str |
String substring(int start) | 從start開始一直到末尾的字符以String的方式返回 |
String substring(int start,int end) | 將[start, end)范圍內的字符以String的方式返回 |
StringBuffer reverse() | 反轉字符串 |
String toString() | 將所有字符按照String的方式返回 |
public static void main(String[] args) {StringBuilder sb1 = new StringBuilder("hello");StringBuilder sb2 = sb1;// 追加:即尾插-->字符、字符串、整形數字sb1.append(' '); // hellosb1.append("world"); // hello worldsb1.append(123); // hello world123System.out.println(sb1); // hello world123System.out.println(sb1 == sb2); // trueSystem.out.println(sb1.charAt(0)); // 獲取0號位上的字符 hSystem.out.println(sb1.length()); // 獲取字符串的有效長度14System.out.println(sb1.capacity()); // 獲取底層數組的總大小sb1.setCharAt(0, 'H'); // 設置任意位置的字符 Hello world123sb1.insert(0, "Hello world!!!"); // Hello world!!!Hello world123System.out.println(sb1);System.out.println(sb1.indexOf("Hello")); // 獲取Hello第一次出現的位置System.out.println(sb1.lastIndexOf("hello")); // 獲取hello最后一次出現的位置sb1.deleteCharAt(0); // 刪除首字符sb1.delete(0,5); // 刪除[0, 5)范圍內的字符String str = sb1.substring(0, 5); // 截取[0, 5)區間中的字符以String的方式返回System.out.println(str);sb1.reverse(); // 字符串逆轉str = sb1.toString(); // 將StringBuffer以String的方式返回System.out.println(str);}
從上述例子可以看出:String和StringBuilder最大的區別在于String的內容無法修改,而StringBuilder的內容可以修改。頻繁修改字符串的情況考慮使用StringBuilder。
注意:String和StringBuilder類不能直接轉換。如果要想互相轉換,可以采用如下原則:
String變為StringBuilder: 利用StringBuilder的構造方法或append()方法
StringBuilder變為String: 調用toString()方法
2.2面試題
1. String、StringBuffer、StringBuilder的區別
(1)String的內容不可修改,StringBuffer與StringBuilder的內容可以修改.
(2)StringBuffer與StringBuilder大部分功能是相似的
(3)StringBuffer采用同步處理,屬于線程安全操作;而StringBuilder未采用同步處理,屬于線程不安全操作
本次內容就到此啦,歡迎評論區或者私信交流,覺得筆者寫的還可以,或者自己有些許收獲的,麻煩鐵汁們動動小手,給俺來個一鍵三連,萬分感謝 !??