《Java從小白到大牛》紙質版已經上架了!!!
html
由字符組成的一串字符序列,稱爲「字符串」,在前面的章節中也屢次用到了字符串,本章將重點介紹。java
Java中的字符串是由雙引號括起來的多個字符,下面示例都是表示字符串常量:程序員
"Hello World" ① "\u0048\u0065\u006c\u006c\u006f\u0020\u0057\u006f\u0072\u006c\u0064" ② "世界你好" ③ "A" ④ "" ⑤
Java中的字符采用Unicode編碼,因此Java字符串能夠包含中文等亞洲字符,見代碼第③行的"世界你好"字符串。代碼第②行的字符串是用Unicode編碼表示的字符串,事實上它表示的也是"Hello World"字符串,可經過System.out.print方法將Unicode編碼表示的字符串輸出到控制檯,則會看到Hello World字符串。api
另外,單個字符若是用雙引號括起來,那它表示的是字符串,而不是字符了,見代碼第④行的"A"是表示字符串A,而不是字符A。數組
注意 字符串還有一個極端狀況,就代碼第⑤行的""表示空字符串,雙引號中沒有任何內容,空字符串不是null,空字符串是分配內存空間,而null是沒有分配內存空間。瀏覽器
Java SE提供了三個字符串類:String、StringBuffer和StringBuilder。String是不可變字符串,StringBuffer和StringBuilder是可變字符串。安全
Java中不少類,每個類又有不少方法和變量,經過查看Java API文檔可以知道這些類、方法和變量如何使用。Java官方爲Java SE提供了基於HTML的API文檔。做爲Java程序員應該熟悉如何使用API文檔。多線程
本節介紹一下如何使用Java SE的API文檔。Java官方提供了Java 8在線API文檔,網址是http://docs.oracle.com/javase/8/docs/api/,頁面如圖9-1所示。oracle
提示 不少讀者但願可以有離線的中文Java API文檔,但Java官方只提供了Java 6的中文API文檔,該文件下載地址是http://download.oracle.com/technetwork/java/javase/6/docs/zh/api.zip,下載完成後解壓api.zip文件,找到其中的index.html文件,雙擊就會在瀏覽器中打開API文檔了。app
下面介紹一下如何使用API文檔,熟悉一下API文檔頁面中的各個部分含義,如圖9-2所示,類和接口中,斜文字體顯示是接口,正常字體纔是類。
在類窗口還有不少內容,向下拖曳滾動條會看到如圖9-3所示頁面,其中「字段摘要」描述了類中的實例變量和靜態變量;「構造方法摘要」描述了類中全部構造方法;「方法摘要」描述了類中全部方法。這些「摘要」只是一個概要說明,單擊連接能夠進入到該主題更加詳細的描述,如圖9-4所示單擊了compareTo方法看到的詳細信息。
查詢API的通常流程是:找包→找類或接口→查看類或接口→找方法或變量。讀者能夠嘗試查找一下String、StringBuffer和StringBuilder這些字符串類的API文檔,熟悉一下這些類的用法。
不少計算機語言都提供了兩種字符串,即不可變字符串和可變字符串,它們區別在於當字符串進行拼接等修改操做時,不可變字符串會建立新的字符串對象,而可變字符串不會建立新對象。
Java中不可變字符串類是String,屬於java.lang包,它也是Java很是重要的類。
提示 java.lang包中提供了不少Java基礎類,包括Object、Class、String和Math等基本類。在使用java.lang包中的類時不須要引入(import)該包,由於它是由解釋器自動引入的。固然引入java.lang包程序也不會有編譯錯誤。
建立String對象能夠經過構造方法實現,經常使用的構造方法:
建立字符串對象示例代碼以下:
// 建立字符串對象 String s1 = new String(); String s2 = new String("Hello World"); String s3 = new String("\u0048\u0065\u006c\u006c\u006f\u0020\u0057\u006f\u0072\u006c\u0064"); System.out.println("s2 = " + s2); System.out.println("s3 = " + s3); char chars[] = { 'a', 'b', 'c', 'd', 'e' }; // 經過字符數組建立字符串對象 String s4 = new String(chars); // 經過子字符數組建立字符串對象 String s5 = new String(chars, 1, 4); System.out.println("s4 = " + s4); System.out.println("s5 = " + s5); byte bytes[] = { 97, 98, 99 }; // 經過byte數組建立字符串對象 String s6 = new String(bytes); System.out.println("s6 = " + s6); System.out.println("s6字符串長度 = " + s6.length());
輸出結果:
s2 = Hello World s3 = Hello World s4 = abcde s5 = bcde s6 = abc s6字符串長度 = 3
上述代碼中s2和s3都是表示Hello World字符串,得到字符串長度方法是length(),其餘代碼比較簡單,這裏再也不贅述。
在前面的學習過程當中細心的讀者可能會發現,前面的示例代碼中得到字符串對象時都是直接使用字符串常量,但Java中對象是使用new關鍵字建立,字符串對象也可使用new關鍵字建立,代碼以下:
String s9 = "Hello"; //字符串常量 String s7 = new String("Hello"); //使用new關鍵字建立
使用new關鍵字與字符串常量都能得到字符串對象,但它們之間有一些區別。先看下面代碼運行結果:
String s7 = new String("Hello"); ① String s8 = new String("Hello"); ② String s9 = "Hello"; ③ String s10 = "Hello"; ④ System.out.printf("s7 == s8 : %b%n", s7 == s8); System.out.printf("s9 == s10: %b%n", s9 == s10); System.out.printf("s7 == s9 : %b%n", s7 == s9); System.out.printf("s8 == s9 : %b%n", s8 == s9);
輸出結果:
s7 == s8 : false s9 == s10: true s7 == s9 : false s8 == s9 : false
==運算符比較的是兩個引用是否指向相同的對象,從上面的運行結果可見,s7和s8指的是不一樣對象,s9和s10指向的是相同對象。
這是爲何?Java中的不可變字符串String常量,採用字符串池(String Pool)管理技術,字符串池是一種字符串駐留技術。採用字符串常量賦值時(見代碼第③行),如圖9-5所示,會字符串池中查找"Hello"字符串常量,若是已經存在把引用賦值給s9,不然建立"Hello"字符串對象,並放到池中。根據此原理,能夠推定s10與s9是相同的引用,指向同一個對象。但此原理並不適用於new所建立的字符串對象,代碼運行到第①行後,會建立"Hello"字符串對象,而它並無放到字符串池中。代碼第②行又建立了一個新的"Hello"字符串對象,s7和s8是不一樣的引用,指向不一樣的對象。
String字符串雖然是不可變字符串,但也能夠進行拼接只是會產生一個新的對象。String字符串拼接可使用+運算符或String的concat(String str)方法。+運算符優點是能夠鏈接任何類型數據拼接成爲字符串,而concat方法只能拼接String類型字符串。
字符串拼接示例以下:
String s1 = "Hello"; // 使用+運算符鏈接 String s2 = s1 + " "; ① String s3 = s2 + "World"; ② System.out.println(s3); String s4 = "Hello"; // 使用+運算符鏈接,支持+=賦值運算符 s4 += " "; ③ s4 += "World"; ④ System.out.println(s4); String s5 = "Hello"; // 使用concat方法鏈接 s5 = s5.concat(" ").concat("World"); ⑤ System.out.println(s5); int age = 18; String s6= "她的年齡是" + age + "歲。"; ⑥ System.out.println(s6); char score = 'A'; String s7= "她的英語成績是" + score; ⑦ System.out.println(s7); java.util.Date now = new java.util.Date(); ⑧ //對象拼接自動調用toString()方法 String s8= "今天是:" + now; ⑨ System.out.println(s8);
輸出結果:
Hello World Hello World Hello World 她的年齡是18歲。 她的英語成績是A 今天是:Thu May 25 16:25:40 CST 2017
上述代碼第①~②行使用+運算符進行字符串的拼接,其中產生了三個對象。代碼第③~④行業是使用+=賦值運算符,本質上也是+運算符進行拼接。
代碼第⑤行採用concat方法進行拼接,該方法的完整定義以下:
public String concat(String str)
它的參數和返回值都是String,所以代碼第⑤行能夠連續調用該方法進行多個字符串的拼接。
代碼第⑥和第⑦行是使用+運算符,將字符串與其餘類型數據進行的拼接。代碼第⑨行是與對象能夠進行拼接,Java中全部對象都有一個toString()方法,該方法能夠將對象轉換爲字符串,拼接過程會調用該對象的toString()方法,將該對象轉換爲字符串後再進行拼接。代碼第⑧行的java.util.Date類是Java SE提供的日期類。
在給定的字符串中查找字符或字符串是比較常見的操做。在String類中提供了indexOf和lastIndexOf方法用於查找字符或字符串,返回值是查找的字符或字符串所在的位置,-1表示沒有找到。這兩個方法有多個重載版本:
[圖片上傳中...(10-6.jpg-790da8-1530662260524-0)]
提示 字符串本質上是字符數組,所以它也有索引,索引從零開始。String的charAt(int index)方法能夠返回索引index所在位置的字符。
字符串查找示例代碼以下:
String sourceStr = "There is a string accessing example."; //得到字符串長度 int len = sourceStr.length(); //得到索引位置16的字符 char ch = sourceStr.charAt(16); //查找字符和子字符串 int firstChar1 = sourceStr.indexOf('r'); int lastChar1 = sourceStr.lastIndexOf('r'); int firstStr1 = sourceStr.indexOf("ing"); int lastStr1 = sourceStr.lastIndexOf("ing"); int firstChar2 = sourceStr.indexOf('e', 15); int lastChar2 = sourceStr.lastIndexOf('e', 15); int firstStr2 = sourceStr.indexOf("ing", 5); int lastStr2 = sourceStr.lastIndexOf("ing", 5); System.out.println("原始字符串:" + sourceStr); System.out.println("字符串長度:" + len); System.out.println("索引16的字符:" + ch); System.out.println("從前日後搜索r字符,第一次找到它所在索引:" + firstChar1); System.out.println("從後往前搜索r字符,第一次找到它所在的索引:" + lastChar1); System.out.println("從前日後搜索ing字符串,第一次找到它所在索引:" + firstStr1); System.out.println("從後往前搜索ing字符串,第一次找到它所在索引:" + lastStr1); System.out.println("從索引爲15位置開始,從前日後搜索e字符,第一次找到它所在索引:" + firstChar2); System.out.println("從索引爲15位置開始,從後往前搜索e字符,第一次找到它所在索引:" + lastChar2); System.out.println("從索引爲5位置開始,從前日後搜索ing字符串,第一次找到它所在索引:" + firstStr2); System.out.println("從索引爲5位置開始,從後往前搜索ing字符串,第一次找到它所在索引:" + lastStr2);
輸出結果:
原始字符串:There is a string accessing example. 字符串長度:36 索引16的字符:g 從前日後搜索r字符,第一次找到它所在索引:3 從後往前搜索r字符,第一次找到它所在的索引:13 從前日後搜索ing字符串,第一次找到它所在索引:14 從後往前搜索ing字符串,第一次找到它所在索引:24 從索引爲15位置開始,從前日後搜索e字符,第一次找到它所在索引:21 從索引爲15位置開始,從後往前搜索e字符,第一次找到它所在索引:4 從索引爲5位置開始,從前日後搜索ing字符串,第一次找到它所在索引:14 從索引爲5位置開始,從後往前搜索ing字符串,第一次找到它所在索引:-1
sourceStr字符串索引如圖9-6所示。上述字符串查找方法比較相似,這裏重點解釋一下sourceStr.indexOf("ing", 5)和sourceStr.lastIndexOf("ing", 5)表達式。從圖9-6可見ing字符串出現過兩次,索引分別是14和24。sourceStr.indexOf("ing", 5)表達式從索引爲5的字符(" ")開始從前日後搜索,結果是找到第一個ing(索引爲14),返回值爲14。sourceStr.lastIndexOf("ing", 5)表達式從索引爲5的字符(" ")開始從後往前搜索,沒有找到,返回值爲-1。
字符串比較是常見的操做,包括比較相等、比較大小、比較前綴和後綴串等。
String提供的比較字符串相等的方法:
有時不只須要知道是否相等,還要知道大小,String提供的比較大小的方法:
字符串比較示例代碼以下:
String s1 = new String("Hello"); String s2 = new String("Hello"); // 比較字符串是不是相同的引用 System.out.println("s1 == s2 : " + (s1 == s2)); // 比較字符串內容是否相等 System.out.println("s1.equals(s2) : " + (s1.equals(s2))); String s3 = "HELlo"; // 忽略大小寫比較字符串內容是否相等 System.out.println("s1.equalsIgnoreCase(s3) : " + (s1.equalsIgnoreCase(s3))); // 比較大小 String s4 = "java"; String s5 = "Swift"; // 比較字符串大小 s4 > s5 System.out.println("s4.compareTo(s5) : " + (s4.compareTo(s5))); ① // 忽略大小寫比較字符串大小 s4 < s5 System.out.println("s4.compareToIgnoreCase(s5) : " + (s4.compareToIgnoreCase(s5))); ② // 判斷文件夾中文件名 String[] docFolder = { "java.docx", " JavaBean.docx", "Objecitve-C.xlsx", "Swift.docx " }; int wordDocCount = 0; // 查找文件夾中Word文檔個數 for (String doc : docFolder) { // 去的先後空格 doc = doc.trim(); ③ // 比較後綴是否有.docx字符串 if (doc.endsWith(".docx")) { wordDocCount++; } } System.out.println("文件夾中Word文檔個數是: " + wordDocCount); int javaDocCount = 0; // 查找文件夾中Java相關文檔個數 for (String doc : docFolder) { // 去的先後空格 doc = doc.trim(); // 所有字符轉成小寫 doc = doc.toLowerCase(); ④ // 比較前綴是否有java字符串 if (doc.startsWith("java")) { javaDocCount++; } } System.out.println("文件夾中Java相關文檔個數是:" + javaDocCount);
輸出結果:
s1 == s2 : false s1.equals(s2) : true s1.equalsIgnoreCase(s3) : true s4.compareTo(s5) : 23 s4.compareToIgnoreCase(s5) : -9 文件夾中Word文檔個數是: 3 文件夾中Java相關文檔個數是:2
上述代碼第①行的compareTo方法按字典順序比較兩個字符串,s4.compareTo(s5)表達式返回結果大於0,說明s4大於s5,字符在字典中順序事實上就它的Unicode編碼,先比較兩個字符串的第一個字符j和S,j的Unicode編碼是106,S的Unicode編碼是83,因此能夠得出結論s4 > s5。代碼第②行是忽略大小寫時,要麼所有當成小寫字母進行比較,要麼當前成所有大寫字母進行比較,不管哪一種比較結果都是同樣的s4 < s5。
代碼第③行trim()方法能夠去除字符串先後空白。代碼第④行toLowerCase()方法能夠將此字符串所有轉化爲小寫字符串,相似的方法還有toLowerCase()方法,可將字符串所有轉化爲小寫字符串。
Java中字符串String截取方法主要的方法以下:
字符串截取方法示例代碼以下:
String sourceStr = "There is a string accessing example."; // 截取example.子字符串 String subStr1 = sourceStr.substring(28); ① // 截取string子字符串 String subStr2 = sourceStr.substring(11, 17); ② System.out.printf("subStr1 = %s%n", subStr1); System.out.printf("subStr2 = %s%n",subStr2); // 使用split方法分割字符串 System.out.println("-----使用split方法-----"); String[] array = sourceStr.split(" "); ③ for (String str : array) { System.out.println(str); }
輸出結果:
subStr1 = example. subStr2 = string -----使用split方法----- There is a string accessing example.
上述sourceStr字符串索引參考圖9-6所示。代碼第①行是截取example.子字符串,從圖9-6可見e字符索引是28, 從索引28字符截取直到sourceStr結尾。代碼第②行是截取string子字符串,從圖9-6可見,s字符索引是11,g字符索引是16,endIndex參數應該17。
另外,String還提供了字符串分割方法,見代碼第③行split(" ")方法,參數是分割字符串,返回值String[]。
可變字符串在追加、刪除、修改、插入和拼接等操做不會產生新的對象。
Java提供了兩個可變字符串類StringBuffer和StringBuilder,中文翻譯爲「字符串緩衝區」。
StringBuffer是線程安全的,它的方法是支持線程同步^8,線程同步會操做串行順序執行,在單線程環境下會影響效率。StringBuilder是StringBuffer單線程版本,Java 5以後發佈的,它不是線程安全的,但它的執行效率很高。
StringBuffer和StringBuilder具備徹底相同的API,即構造方法和方法等內容同樣。StringBuilder的中構造方法有4個:
上述構造方法一樣適合於StringBuffer類,這裏再也不贅述。
提示 字符串長度和字符串緩衝區容量區別。字符串長度是指在字符串緩衝區中目前所包含字符串長度,經過length()得到;字符串緩衝區容量是緩衝區中所能容納的最大字符數,經過capacity()得到。當所容納的字符超過這長度時,字符串緩衝區自動擴充容量,但這是以犧牲新能爲代價的擴容。
字符串長度和字符串緩衝區容量示例代碼以下:
// 字符串長度length和字符串緩衝區容量capacity StringBuilder sbuilder1 = new StringBuilder(); System.out.println("包含的字符串長度:" + sbuilder1.length()); System.out.println("字符串緩衝區容量:" + sbuilder1.capacity()); StringBuilder sbuilder2 = new StringBuilder("Hello"); System.out.println("包含的字符串長度:" + sbuilder2.length()); System.out.println("字符串緩衝區容量:" + sbuilder2.capacity()); // 字符串緩衝區初始容量是16,超過以後會擴容 StringBuilder sbuilder3 = new StringBuilder(); for (int i = 0; i < 17; i++) { sbuilder3.append(8); } System.out.println("包含的字符串長度:" + sbuilder3.length()); System.out.println("字符串緩衝區容量:" + sbuilder3.capacity());
輸出結果:
包含的字符串長度:0 字符串緩衝區容量:16 包含的字符串長度:5 字符串緩衝區容量:21 包含的字符串長度:17 字符串緩衝區容量:34 ### 字符串追加 {#-0}
StringBuilder在提供了不少修改字符串緩衝區的方法,追加、插入、刪除和替換等,這一節先介紹字符串追加方法。字符串追加方法是append,append有不少重載方法,能夠追加任何類型數據,它的返回值仍是StringBuilder。StringBuffer的追加法與StringBuffer徹底同樣,這裏再也不贅述。
字符串追加示例代碼以下:
//添加字符串、字符 StringBuilder sbuilder1 = new StringBuilder("Hello"); ① sbuilder1.append(" ").append("World"); ② sbuilder1.append('.'); ③ System.out.println(sbuilder1); StringBuilder sbuilder2 = new StringBuilder(); Object obj = null; //添加布爾值、轉義符和空對象 sbuilder2.append(false).append('\t').append(obj); ④ System.out.println(sbuilder2); //添加數值 StringBuilder sbuilder3 = new StringBuilder(); for (int i = 0; i < 10; i++) { sbuilder3.append(i); } System.out.println(sbuilder3);
運行結果:
Hello World. false null 0123456789
上述代碼第①行是建立一個包含Hello字符串StringBuilder對象。代碼第②行是兩次連續調用append方法,因爲全部的append方法都返回StringBuilder對象,全部能夠連續調用該方法,這種寫法比較簡潔。若是連續調用append方法不行喜歡,能夠append方法佔一行,見代碼第③行。
代碼第④行連續追加了布爾值、轉義符和空對象,須要注意的是布爾值false轉換爲false字符串,空對象null也轉換爲"null"字符串。
StringBuilder中實現插入、刪除和替換等操做的經常使用方法說明以下:
以上介紹的方法雖然是StringBuilder方法,但StringBuffer也徹底同樣,這裏再也不贅述。
示例代碼以下:
// 原始不可變字符串 String str1 = "Java C"; // 從不可變的字符建立可變字符串對象 StringBuilder mstr = new StringBuilder(str1); // 插入字符串 mstr.insert(4, " C++"); ① System.out.println(mstr); // 具備追加效果的插入字符串 mstr.insert(mstr.length(), " Objective-C"); ② System.out.println(mstr); // 追加字符串 mstr.append(" and Swift"); System.out.println(mstr); // 刪除字符串 mstr.delete(11, 23); ③ System.out.println(mstr);
運行輸出結果:
Java C++ C Java C++ C Objective-C Java C++ C Objective-C and Swift Java C++ C and Swift
上述代碼第①行mstr.insert(4, " C++")是在索引4,插入字符串,原始字符串索引如同9-7所示,索引4位置是一個空格,在它以前插入字符串。代碼第②行mstr.insert(mstr.length(), " Objective-C")是按照字符串的長的插入,也就是在尾部追加字符串。在執行代碼第③行刪除字符串以前的字符串如圖9-8所示,mstr.delete(11, 23)語句是要刪除"Objective-C "子字符串,第一個參數是子字符串開始索引11;第二個參數是23,結束字符的索引是22(end - 1),因此參數end是23。
本週介紹了Java中的字符串,Java字符串類分爲:可變字符串類(String)和不可變字符串類(StringBuilder和StringBuffer)。而後分別介紹了這些字符串類的用法。
http://edu.51cto.com/topic/1246.html
http://www.zhijieketang.com/group/5