目錄
1. String類的重要性
2. 常用方法
2.1 字符串構造
2.2 String對象的比較
2.3 字符串查找
2.4 轉化
2.5 字符串替換
2.6 字符串拆分
2.7 字符串截取
2.8 其他操作方法
2.9 字符串的不可變性
2.10 字符串修改
3. StringBuilder和StringBuffer
3.1 StringBuilder的介紹
3.2 面試題:
4. String類oj
正文開始
1. String類的重要性
在C語言中已經涉及到字符串了,但是在C語言中要表示字符串只能使用字符數組或者字符指針,可以使用標準庫提 供的字符串系列函數完成大部分操作,但是這種將數據和操作數據方法分離開的方式不符合面相對象的思想,而字 符串應用又非常廣泛,因此Java語言專門提供了String類。
在開發和校招筆試中,字符串也是常客,比如:
字符串轉整形數字
字符串相加
而且在面試中也頻繁被問到,比如:String、StringBuff和StringBulider之間的區別等。
2. 常用方法
2.1 字符串構造
String類提供的構造方式非常多,常用的就以下三種:
public static void main(String[] args) {
// 使用常量串構造
String s1 = "hello world";
System.out.println(s1);
// 直接newString對象
String s2 = new String("hello world");
System.out.println(s1);
// 使用字符數組進行構造
char[] array = {'h','e','l','l','w','o','r','l','d'};
String s3 = new String(array);
System.out.println(s1);
}
其他方法需要用到時,大家參考Java在線文檔:String官方文檔
【注意】
????????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;
System.out.println(s1.length()); // 獲取字符串長度---輸出5
System.out.println(s1.isEmpty()); // 如果字符串長度為0,返回true,否則返回false
}
?????????2. 在Java中“”引起來的也是String類型對象。
// 打印"hello"字符串(String對象)的長度
System.out.println("hello".length());
2.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); // false
System.out.println(a == c); // true// 對于引用類型變量,==比較兩個引用變量引用的是否為同一個對象
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = new String("world");
String s4 = s1;
System.out.println(s1 == s2); // false
System.out.println(s2 == s3); // false
System.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 是否為同一個對象比較,如果是返回true
if (this == anObject) {
return true;
}
// 2. 檢測anObject是否為String類型的對象,如果是繼續比較,否則返回false
if (anObject instanceof String) {
// 將anObject向下轉型為String類型對象
String anotherString = (String)anObject;
int n = value.length;
// 3. this和anObject兩個字符串的長度是否相同,是繼續比較,否則返回false
if (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引用的是三個不同對象,因此==比較結果全部為false
System.out.println(s1 == s2); // false
System.out.println(s1 == s3); // false
// equals比較:String對象中的逐個字符
// 雖然s1與s2引用的不是同一個對象,但是兩個對象中放置的內容相同,因此輸出true
// s1與s3引用的不是同一個對象,而且兩個對象中內容也不同,因此輸出false
System.out.println(s1.equals(s2)); // true
System.out.println(s1.equals(s3)); // false
}
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
}
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
}
比
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)); // 不同輸出字符差值-1
System.out.println(s1.compareTo(s3)); // 相同輸出 0
System.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
}
2.3 字符串查找
字符串查找也是字符串中非常常見的操作,String類提供的常用查找的方法:
?
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
}
注意:上述方法都是實例方法。
2.4 轉化
1. 數值和字符串轉化
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);
System.out.println(s2);
System.out.println(s3);
System.out.println(s4);
System.out.println("=================================");
// 字符串轉數字
// 注意:Integer、Double等是Java中的包裝類型
int data1 = Integer.parseInt("1234");
double data2 = Double.parseDouble("12.34");
System.out.println(data1);
System.out.println(data2);
}
2. 大小寫轉換
public static void main(String[] args) {
String s1 = "hello";
String s2 = "HELLO";
// 小寫轉大寫
System.out.println(s1.toUpperCase());
// 大寫轉小寫
System.out.println(s2.toLowerCase());
}
3. 字符串轉數組
public static void main(String[] args) {
String s = "hello";
// 字符串轉數組
char[] ch = s.toCharArray();
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);
}
2.5 字符串替換
使用一個指定的新的字符串替換掉已有的字符串數據,可用的方法如下:
?代碼示例: 字符串的替換處理
String str = "helloworld" ;
System.out.println(str.replaceAll("l", "_"));
System.out.println(str.replaceFirst("l", "_"));
注意事項: 由于字符串是不可變對象, 替換不修改當前字符串, 而是產生一個新的字符串.
2.6 字符串拆分
可以將一個完整的字符串按照指定的分隔符劃分為若干個子字符串。
可用方法如下:
?代碼示例: 實現字符串的拆分處理
String str = "hello world hello java" ;
String[] result = str.split(" ") ; // 按照空格拆分
for(String s: result) {
System.out.println(s);
}
代碼示例: 字符串的部分拆分
String str = "hello world hello bit" ;
String[] result = str.split(" ",2) ;
for(String s: result) {
System.out.println(s);
}
拆分是特別常用的操作. 一定要重點掌握. 另外有些特殊字符作為分割符可能無法正確切分, 需要加上轉義.
代碼示例: 拆分IP地址
String str = "192.168.1.1" ;
String[] result = str.split("\\.") ;
for(String s: result) {System.out.println(s);
}
注意事項:
????????1. 字符"|","*","+"都得加上轉義字符,前面加上 "\\" .
????????2. 而如果是 "\" ,那么就得寫成 "\\\\" .
????????3. 如果一個字符串中有多個分隔符,可以用"|"作為連字符.
代碼示例: 多次拆分
String str = "name=zhangsan&age=18" ;
String[] result = str.split("&") ;
for (int i = 0; i < result.length; i++) {String[] temp = result[i].split("=") ;System.out.println(temp[0]+" = "+temp[1]);
}
這種代碼在以后的開發之中會經常出現
2.7 字符串截取
從一個完整的字符串之中截取出部分內容。可用方法如下:
?代碼示例: 觀察字符串截取
String str = "helloworld" ;
System.out.println(str.substring(5));
System.out.println(str.substring(0, 5));
注意事項:
1. 索引從0開始
2. 注意前閉后開區間的寫法, substring(0, 5) 表示包含 0 號下標的字符, 不包含 5 號下標
2.8 其他操作方法
?代碼示例: 觀察trim()方法的使用
String str = " hello world " ;
System.out.println("["+str+"]");
System.out.println("["+str.trim()+"]");
trim 會去掉字符串開頭和結尾的空白字符(空格, 換行, 制表符等).
代碼示例: 大小寫轉換
String str = " hello%$$%@#$%world 哈哈哈 " ;
System.out.println(str.toUpperCase());
System.out.println(str.toLowerCase());
這兩個函數只轉換字母
2.9 字符串的不可變性
String是一種不可變對象. 字符串中的內容是不可改變。字符串不可被修改,是因為:
1. String類在設計時就是不可改變的,String類實現描述中已經說明了
以下來自JDK1.8中String類的部分實現:
?String類中的字符實際保存在內部維護的value字符數組中,該圖還可以看出:
????????1. String類被final修飾,表明該類不能被繼承
????????2. value被修飾被final修飾,表明value自身的值不能改變,即不能引用其它字符數組,但是其引用空間中 的內容可以修改。
2. 所有涉及到可能修改字符串內容的操作都是創建一個新對象,改變的是新對象
【糾正】網上有些人說:字符串不可變是因為其內部保存字符的數組被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分配值
}
2.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
3. StringBuilder和StringBuffer
3.1 StringBuilder的介紹
由于String的不可更改特性,為了方便字符串的修改,Java中又提供StringBuilder和StringBuffer類。這兩個類大 部分功能是相同的,這里介紹 StringBuilder常用的一些方法,其它需要用到了大家可參閱 StringBuilder在線文檔
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類不能直接轉換。如果要想互相轉換,可以采用如下原則:
? ? ? ?1. String變為StringBuilder: 利用StringBuilder的構造方法或append()方法
? ? ? ? 2.StringBuilder變為String: 調用toString()方法。
3.2 面試題:
1. String、StringBuffer、StringBuilder的區別
String的內容不可修改,StringBuffer與StringBuilder的內容可以修改. StringBuffer與StringBuilder大部分功能是相似的 StringBuffer采用同步處理,屬于線程安全操作;而StringBuilder未采用同步處理,屬于線程不安全操 作
2. 以下總共創建了多少個String對象【前提不考慮常量池之前是否存在】
String str = new String("ab"); // 會創建多少個對象
String str = new String("a") + new String("b"); // 會創建多少個對象
4. String類oj
1.第一個只出現一次的字符
class Solution {public int firstUniqChar(String s) {int[] count = new int[256];// 統計每個字符出現的次數for(int i = 0; i < s.length(); ++i){count[s.charAt(i)]++;}// 找第一個只出現一次的字符for(int i = 0; i < s.length(); ++i){if(1 == count[s.charAt(i)]){return i;}}return -1;}
}
2. 最后一個單詞的長度
import java.util.Scanner;public class Main{public static void main(String[] args){// 循環輸入Scanner sc = new Scanner(System.in);while(sc.hasNext()){// 獲取一行單詞String s = sc.nextLine();// 1. 找到最后一個空格// 2. 獲取最后一個單詞:從最后一個空格+1位置開始,一直截取到末尾// 3. 打印最后一個單詞長度int len = s.substring(s.lastIndexOf(' ')+1, s.length()).length();System.out.println(len);}sc.close();}
}
3. 檢測字符串是否為回文
class Solution {public boolean isPalindrome(String s){s = s.toLowerCase();int left = 0;int right = s.length()-1;while (left < right){while (left < right && !isNumberAndCharacter(s.charAt(left))){left++;}while (left < right && !isNumberAndCharacter(s.charAt(right))){right--;}if(s.charAt(left) == s.charAt(right)){left++;right--;}else {return false;}}return true;}private boolean isNumberAndCharacter(char ch){if (Character.isDigit(ch) || Character.isLetter(ch)){return true;}return false;}}
完