1.String類的重要性
經過了C語言的學習,我們認識了字符串,但在C語言中,我們表示字符串進行操作的話需要通過字符指針或者字符數組,可以使用標準庫中提供的一系列方法對字符串的內容進行操作,但這種表達和操作數據的方法不太符合面向對象的思想,所以在Java中提供了String類。
2. 認識String類
在Java中,String類是一種存儲字符串數據類型的類。在Java中,String類屬于引用數據類型,由String類創建的對象里面存的是引用。
2.1 字符串構造
在Java中,字符串的構造有很多種方式,常用的就以下三種。
public class Test {public static void main(String[] args) {//使用常量直接構造String s1="haha";System.out.println(s1);//直接new String對象String s2=new String("man");System.out.println(s2);//使用字符數組進行構造char[] array={'w','c','I','s'};String s3=new String(array);System.out.println(s3);}
}
運行代碼
2.2 深刻認識String類
我們知道String類的對象里面存的是引用,那字符串的內容具體是存在哪里的呢?
上圖是String類里面的一些具體細節,發現里面有一個char[ ]?value數組,所以字符串就是存儲在這個數組中。
String類的堆棧圖
2.3 String類的比較?
?1. 用 == 比較
當我們用 == 進行String類的對象進行比較時,是比較對象里面存的引用的值。
public class Test {public static void main(String[] args) {String s1="man";String s2=new String("man");String s3=s1;System.out.println(s1==s2);System.out.println(s1==s3);System.out.println(s2==s3);}
}
2. equal()方法比較
用equal方法比較String類的對象時,比較的是對象的字符串的內容是否相同。
public class Test {public static void main(String[] args) {String s1="haha";String s2=new String("man");String s3=s1;System.out.println(s1.equals(s2));System.out.println(s1.equals(s3));System.out.println(s2.equals(s3));}
}
?3.int compareTo(String s)方法比較
1.當我們使用 int compareTo(String s) 方法比較時,比較的規則是:兩個字符串對應位置上的的字母比較,直到比到對應的字母不同時,看哪個字母的ASCII值大,對應的那個字符串就長。就直接放回對應兩個字母的ASCII值的差值。
2.當比較的兩個字符串的長度不一樣,一個長,一個短,假設短的字符串的長度為k,如果短的字符串的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) 方法
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
}
5.易錯點(超級重點)
public static void main(String[] args) {String s1="hhh";String s2="hhh";System.out.println(s1==s2);//結果為true}
這時候因為s1和s2都是直接賦值,且內容一樣,這時編譯器會默認s1和s2指向同一塊空間。
3.String類的常用方法
3.1 字符串查找
下圖是一些Java中常用的字符串查找功能的方法。
charAt(int index) 方法
用來查找字符串中指定位置上的字符
public class Test {public static void main(String[] args) {String str="manlebron";System.out.println(str.charAt(4));//輸出e}
}
以上代碼是查找字符串中下標為4的字符,是e。
int indexOf(int ch)方法
用來查找指定字符第一次出現的位置
public class Test {public static void main(String[] args) {String str="manlebron";System.out.println(str.indexOf('n'));}
}
int indexOf(int ch, int fromIndex)方法
用來在字符串中從fromIndex位置開始尋找第一次出現字符ch的位置
public class Test {public static void main(String[] args) {String str="manlebron";System.out.println(str.indexOf('l',2));}
}
int indexOf(String str)?方法
用來查找str第一次在字符串中出現的位置
public class Test {public static void main(String[] args) {String str="manlebron";System.out.println(str.indexOf("le"));}
}
由于剩下的方法用法差不多,就不 一 一 介紹了。
3.2 字符串轉換
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);
}
?4.字符串替換
用來將一個字符串替換原有字符串中指定的一部分。
public static void main(String[] args) {String str = "helloworld" ;System.out.println(str.replaceAll("l", "_"));System.out.println(str.replaceFirst("l", "_"));}
?5. 字符串拆分------split方法
用來將一個字符串按指定的分割符將原來的字符串分割成多個字符串。
public static void main(String[] args) {String str = "hello world hello bit" ;String[] result = str.split(" ") ; // 按照空格拆分for(String s: result) {System.out.println(s);}}
?部分拆分
public static void main(String[] args) {String str = "hello world hello bit" ;String[] result = str.split(" ",3) ; // 按照空格拆分,分為3組for(String s: result) {System.out.println(s);}}
注意事項:拆分是常用的操作,一定要重點掌握。另外,有些特殊的字符無法直接進行拆分,需要加上轉移符號 ' \\?' 。
如拆分IP地址
?如以下代碼
public class Test {public static void main(String[] args) {String IP="192.168.1.1";String s[]=IP.split(".");for(String tmp:s){System.out.println(tmp);}}
}
運行代碼
5.1 特殊字符的拆分?
1.點字符
我們發現什么輸出都沒有,這也就意味這分割沒成功,因為 " . "是一個特殊的操作符,需要加上轉義符號 " \\ " 。
修改如下
public class Test {public static void main(String[] args) {String IP="192.168.1.1";String s[]=IP.split("\\."); //在 " . " 前加\\for(String tmp:s){System.out.println(tmp);}}
}
運行代碼
?2. " \ " 字符
由于 \ 是一個整除符號,想要在表示 \ 是一個普通的斜桿,就必須在前面再加一個 \ 。
所以將其作為分割符時,要寫成 "\\\\".
public static void main(String[] args) {String str="haha\\man\\what\\can\\I\\say?";for(String tmp:str.split("\\\\")){System.out.println(tmp);}}
5.2?多次拆分
當一個字符串中有多個字符時,我們可以進行多次拆分。
public static void main(String[] args) {String IP="192&man.168.1.1&haha";String s[]=IP.split("\\."); //在 " . " 前加\\for(String tmp:s){for(String tmp2:tmp.split("&")){System.out.println(tmp2);}}}
運行代碼:z
我們也可以用 “ | ” 作為連字符,進行有多個字符的字符串進行拆分。
public static void main(String[] args) {String IP="192&man.168.1.1&haha";for(String tmp:IP.split("&|\\.")){System.out.println(tmp);}}
注意:不能在指定的分隔符前加上一個空格,因為空格也算一個字符。?
public static void main(String[] args) {String IP="192&man.168.1.1&haha";for(String tmp:IP.split("\\. | &")){System.out.println(tmp);}}
如上圖所示,在分隔符前加一個空格,效果就變得不一樣了。因為加了空格之后,分隔符就變成了“分隔符+空格”。
?5.3 小總結
1.字符?" | " , " * " , " + "都得加上轉義字符,前面加上 " \\ " 。
2.??而如果是??" \ " ,那么就得寫成 " \\\\ " 。
3.?如果一個字符串中有多個分隔符,可以用"|"作為連字符。
6. 字符串截取-----substring方法
以上的substring方法是用來截取字符串中的一部分內容的。
代碼演示
public static void main(String[] args) {String str = "helloworld" ;System.out.println(str.substring(5));System.out.println(str.substring(0, 5));//左開右閉 [0,5)}
7.其他方法---trim( )方法
trim( ) 方法是用來除去字符串兩邊的空格的,但并不會出去字符串里面的空格。
代碼演示
public static void main(String[] args) {String str=" what can I say ";String s=str.trim();System.out.println(s);}
8. 字符串的不可變性
首先,我們要清楚,只要涉及到String類型的轉變都不是在原字符串上進行的修改,原理是產生一個新的對象。?
?1.string類在設計時就是被設計為無法改變的,在String類中已經具體描述了,如下圖:
從該圖中還可以看出,字符串的內容是保存在char[ ] value 數組中的。
String類是如何設計成無法改變的呢?
一直有人誤認為String類之所以無法被改變是因為String類被final修飾或者string類中的那個數組被final修飾,其實這些都是錯誤的。
因為一個類被final修飾只能表明這個類無法被繼承,一個數組被final修飾,表示數組名存的引用無法被改變。這些都與String類無法被改變有聯系。
真正的原因是,存放字符串的那個數組被private修飾了,且String類內沒有提供任何方法來讓外界去訪問和使用該數組,所以就造成了字符串的不可變性。
10.字符串的修改
注意:我們要盡量避開對字符串的直接修改,因為String類是無法被改變的,所有的修改都會創建新的對象,會導致效率非常底下。
如以下代碼:
public static void main(String[] args) {String s = "hello";s += " world";System.out.println(s); // 輸出:hello world}
這段代碼看似很簡單,有看起來像直接對String類進行了修改。其實不然,
在這段代碼的背后做了很多工作,先是創建了一個StringBuilder對象,在原來s中字符串的內容存到StringBuilder對象里面,然后在對StringBuilder對象進行了修改,然后再通過toString()方法轉換為String類型,最后再放回一個新的String類的對象。
如下圖
這里創建了很多臨時變量,就導致了效率低下。
因此我們要盡量避免對String類的直接改變,如果要修改建議盡量 使用StringBuffer或者StringBuilder。
11.StringBuilder和StringBuffer
由于String類型無法直接被改變,再Java中提供了StringBuilder和StringBuffer類,這兩個類也是可以存儲字符串的,但可以直接對字符串修改的。
public static void main(String[] args) {StringBuilder stringBuilder=new StringBuilder("haha ");System.out.println(stringBuilder.append("man"));StringBuffer stringBuffer=new StringBuffer("what can I say");stringBuffer.append("?");System.out.println(stringBuffer);}
其實?StringBuilder和StringBuffer的用法很相似,就一個區別。
如上圖StringBuffer中多了一個synchronized,這個可以理解為一把鎖,在多線程的情況下可以保證安全。
而StringBuilder主要是在單線程情況下使用。
StringBuilder和StringBuffer和String的區別
1.?String的內容不可修改,StringBuffer與StringBuilder的內容可以修改.