String字符串
char類型只能表示一個字符,而String可以表示字符串,也就是一個字符序列。但String不是基本類型,而是一個定義好的類,是一個引用類型。在Java中,可以將字符串直接量賦給String類型變量,也可以采用new String(parameter)的形式來創建字符串。
String str = "This is String”; //用字符串直接量賦值
String str = new String("Create a String through the Constructor"); //String的構造器來創建字符串
這里表示引用變量str,引用一個內容為This is String 的字符串對象。 但通常情況下,可直接稱str變量是一個字符串,無須過於強調細節。
字符串特點:String類是不可變類,並且被final修飾,無法繼承。 字符串對象都是不可變對象,所以對字符串進行操作時,都是返回新的字符串對象,原有字符串不會改變。
字符串在程序設計中用得非常頻繁,所以掌握String字符串的常用方法是很有必要的。例如:
String普通方法
length() //返回字符串中的字符數,即字符串長度。 charAt(int index) //根據索引位置,返回對應字符。 toLowerCase() //把字符串中所有字母字符變成小寫。 toUpperCase() //把字符串中所有字母字符變成大寫。 toCharArray() //把字符串轉成字符數組,即一個字符對應一個字符數組元素。 trim() //消除字符串的兩邊空白字符。
String s = "ABCDEF"; System.out.println(s.length()); //6 System.out.println(s.charAt(0)); //索引位置0是 A String lowerCase = s.toLowerCase(); System.out.println(lowerCase); //abcdef char[] ch = s.toCharArray(); System.out.println(ch[0]); // A System.out.println(" ABC ".trim()); //ABC
String比較方法
equals(Object anObject) //判斷當前字符串對象與指定對象是否相等。 equalsIgnoreCase(String anotherString) //判斷當前字符串對象與指定String 對象是否相等,忽略大小寫。 compareTo(String anotherString) //按字典順序比較兩個字符串。 compareToIgnoreCase(String str) //按字典順序比較兩個字符串,忽略大小寫 boolean startsWith(String prefix) //判斷是否以指定字符串作為前綴 boolean startsWith(String prefix, int toffset) //從指定的索引處開始,判斷是否以指定字符串作為前綴 boolean endsWith(String suffix) //當前字符串是否以指定字符串作為后綴。 contains(CharSequence s) //如果包含指定字符串,則返回 true。否則false
注意:比較兩個字符串內容是否相等時,很多人都會用 ==操作符來比較,但這是錯的,下面說一下它們的區別。
==操作符和equals方法的區別
操作符==比較的是變量值是否相同,因為字符串是引用類型,所以操作符==只能檢測兩個字符串是否指向同一個引用(對象地址),但無法檢測字符串對象的內容。操作符==只能用於判斷基本類型以及引用類型是否為null。
要判斷兩個字符串變量是否相同,應該使用equals()方法來判斷。兩個對象指向同一引用,則說明內容相等。否則開始循環比較字符串內容。String的equals()方法實現細節:
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
String s = "This is String"; String s1 = s + ""; //產生一個新字符串 System.out.println(s == s1); //兩個字符串對象非同一個引用,返回false System.out.println(s.equals(s1)); //兩個字符串對象的內容相等,返回true
總結一下就是:操作符==是直接比較變量的值。若是引用類型變量,則比較引用地址是否相同。而equals()方法是比較引用對象中的內容。
演示其他比較方法
String s = "hello world"; System.out.println(s.equalsIgnoreCase("HELLO WORLD")); //忽略大小寫,比較字符串內容。true //輪流比較字符,字符不相等時,返回字符相減結果:e - a = 4 [69- 65] System.out.println(s.compareTo("hallo world")); //判斷前綴 System.out.println(s.startsWith("hello")); //true //判斷后綴 System.out.println(s.endsWith("worlds")); // false //是否包含指定字符串 System.out.println(s.contains("lo wor")); //空白字符串也屬於字符,別忽略了
除此之外,還有截取子字符串substring()、切割字符串split()、根據索引找字符串indexOf()、lastIndexOf()以及替換相應字符串replace()等等方法。若要了解更多方法,可查閱API。
轉換字符串
有時候,我們需要將某個類型轉成字符串來進行操作。例如將數值類型轉成字符串,可以很快判斷是幾位數,可以快速判斷是否是回文數。
方式有兩種:采用操作符+拼接成字符串;通過靜態方法valueOf(parameter)將相關類型轉成對應字符串。
String s1 = String.valueOf(123);
String s2 = 123 +"";
采用操作符+直接轉成字符串是最簡潔、最方便的。
字符串直接量與new String()的區別
String s1 = "ABC"; String s2 = new String(s1); //等價於 new String("ABC"); String s3 = s1 + ""; System.out.println(s1 == s2); //false System.out.println(s1 == s3); //false
字符串直接量是一個字符串對象,而new String(s1)會構建一個同類型但不同內存空間的字符串對象。簡單來說就是,兩者沒有指向同一個引用。所以操作符==判斷為false。
s3 = s1 + ""; 這一段是運行時對字符串變量s1進行拼接,所以會產生一個新的字符串對象。所以為false。
關於對字符串直接量拼接是否相等同內容字符串
如果直接對字符串直接量進行拼接,而非采用變量形式拼接字符串,比較結果又會不同。
String c = "C"; String s1 = "ABC"; String s2 = "AB" + c; String s3 = "A" + "B" + "C"; System.out.println(s1 == s2); //false System.out.println(s1 == s3); //true
因為字符串是常量,所以創建“ABC”這個字符串時,會放在常量池中。 但s2指向的字符串對象引用是到運行時才會確定, 所以會導致創建一個新字符串對象。而s3是以字符串直接量來進行拼接,這些字符串在編譯時就能確定下來,編譯器就在常量池查找是否存在相同的字符串。若已存在,指向同一個字符串對象,否則,另外創建字符串。
除了操作符==判斷引用地址外,可以使用System.identityHashcode() 查看內存地址是否相同,identityHashcode() 是根據內存地址生成的哈希值。
可變字符串StringBuilder、StringBuffer
String是不可變類,字符串都是常量,例如“ABC”會被存儲在常量池中。對字符串進行任何更改操作都會產生新的String對象。而StringBuilder與StringBuffer是可變類,它們的字符串對象可以更改,對可變字符串的操作不會生成新的對象,即對同一個字符串對象操作。
StringBuilder、StringBuffer創建字符串
StringBuilder sb = new StringBuilder(); //空字符串 StringBuilder sb1 = new StringBuilder("字符串"); //以String對象作為參數構建字符串
StringBuilder與StringBuffer構建可變字符串對象都是通過new操作符調用構造方法,不能直接像String一樣接收字符串直接量。
StringBuilder和StringBuffer的使用方式一模一樣,兩者只需要修改一下類名就可以無縫切換。兩者的區別是StringBuilder應用於單線程環境,而StringBuffer應用於多線程環境。所以接下來只以StringBuilder作為示例。
可變字符串的常用方法(增刪改查)
append(data) //將給定數據作為字符串追加到可變字符串尾部 insert(offset, data) //將給定數據作為字符串追加到指定的偏移位置 delete(start, end); //刪除start 到 end -1 的字符 replace(start, end, str) //替換start 到 end -1 的字符 reverse(); //將該字符串進行倒置 sb.setCharAt(index, ch);; //設置 index 處的字符為給定字符
StringBuilder sb = new StringBuilder(); //構建空的可變字符串 sb.append("String is changed"); System.out.println(sb); //原字符串對象內容被改變 String is changed //在下標0處插入123 sb.insert(0, 123); System.out.println(sb); //123String is changed //刪除 sb字符串的后面7位字符 sb.delete(sb.length() - 7, sb.length()); System.out.println(sb); //123String is //替換前三位字符 sb.replace(0, 3, "!!!"); System.out.println(sb); //!!!String is //翻轉sb字符串 sb.reverse(); System.out.println(sb); // si gnirtS!!! //設置某個下標的字符內容 sb.setCharAt(0,'A'); System.out.println(sb); //Asi gnirtS!!!
可以看到,對可變字符串作出任何更改操作,都會對其字符串對象進行操作。 相比於String,若是需要大量使用字符串的場景,建議采用可變字符串,可以節省很多內存空間。
使用可變字符串的場景
1.將數組內容轉成字符串
public static String toStringWithArray(int[] arr) { StringBuilder sb = new StringBuilder("["); for(int i = 0; i < arr.length; i++) { if(i != arr.length -1) { sb.append(arr[i] + ", "); }else { sb.append(arr[i] + "]"); } } return sb.toString(); }
如果不采用可變字符串,那么在拼接字符串過程中,會產生很多用不到的字符串對象,很浪費內存空間。
凡是需要大量拼接字符串的地方,都應該盡量使用可變字符串來完成,因為效率高,而且不占內存空間。