字符串普遍應用 在Java 編程中,在 Java 中字符串屬於對象,Java 提供了 String 類來建立和操做字符串。面試
String定義:正則表達式
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {}
複製代碼
String設計爲不可變類主要考慮到:效率和安全。編程
爲了避免浪費你的時間,請看下面的題目,若你一目瞭然,能夠跳過本文了。api
public class Test {
public static void main(String[] args) {
String str1 = "HelloFlyapi";
String str2 = "HelloFlyapi";
String str3 = new String("HelloFlyapi");
String str4 = "Hello";
String str5 = "Flyapi";
String str6 = "Hello" + "Flyapi";
String str7 = str4 + str5;
System.out.println("str1 == str2 result: " + (str1 == str2));
System.out.println("str1 == str3 result: " + (str1 == str3));
System.out.println("str1 == str6 result: " + (str1 == str6));
System.out.println("str1 == str7 result: " + (str1 == str7));
System.out.println("str1 == str7.intern() result: " + (str1 == str7.intern()));
System.out.println("str3 == str3.intern() result: " + (str3 == str3.intern()));
}
}
複製代碼
從上面的題中你會知道,String的建立方式有兩種:數組
String str = "flyapi";
複製代碼
此方式在堆內存建立對象緩存
String str = new String();
複製代碼
要理解String,那麼要了解JVM內存中的棧(stack)、堆(heap)和方法區。簡要圖以下:安全
str1 == str2bash
String str1 = "HelloFlyapi";
String str2 = "HelloFlyapi";
System.out.println(str1 == str2); // true
複製代碼
當執行第一句時,JVM會先去常量池中查找是否存在HelloFlyapi,當存在時直接返回常量池裏的引用;當不存在時,會在字符創常量池中建立一個對象並返回引用。微信
當執行第二句時,一樣的道理,因爲第一句已經在常量池中建立了,因此直接返回上句建立的對象的引用。
str1 == str3
String str1 = "HelloFlyapi";
String str3 = new String("HelloFlyapi");
System.out.println(str1 == str3); // false
複製代碼
執行第一句,同上第一句。
執行第二句時,會在堆(heap)中建立一個對象,當字符創常量池中沒有‘HelloFlyapi’時,會在常量池中也建立一個對象;當常量池中已經存在了,就不會建立新的了。
str1 == str6
String str1 = "HelloFlyapi";
String str6 = "Hello" + "Flyapi";
System.out.println(str1 == str6); // true
複製代碼
因爲"Hello"和"Flyapi"都是常量,編譯時,第二句會被自動編譯爲‘String str6 = "HelloFlyapi";’
str1 == str7
String str1 = "HelloFlyapi";
String str4 = "Hello";
String str5 = "Flyapi";
String str7 = str4 + str5;
System.out.println(str1 == str7); // false
複製代碼
其中前三句變量存儲的是常量池中的引用地址。
第四句執行時,JVM會在堆(heap)中建立一個以str4爲基礎的一個StringBuilder對象,而後調用StringBuilder的append()方法完成與str5的合併,以後會調用toString()方法在堆(heap)中建立一個String對象,並把這個String對象的引用賦給str7。
下面是 String 類支持的方法,更多詳細,參看 Java String API 文檔:
方法 | 描述 |
---|---|
char charAt(int index) | 返回指定索引處的 char 值。 |
int compareTo(Object o) | 把這個字符串和另外一個對象比較。 |
int compareTo(String anotherString) | 按字典順序比較兩個字符串。 |
boolean endsWith(String suffix) | 測試此字符串是否以指定的後綴結束。 |
boolean equals(Object anObject) | 將此字符串與指定的對象比較。 |
boolean equalsIgnoreCase(String anotherString) | 將此 String 與另外一個 String 比較,不考慮大小寫。 |
byte[] getBytes() | 使用平臺的默認字符集將此 String 編碼爲 byte 序列,並將結果存儲到一個新的 byte 數組中。 |
byte[] getBytes(String charsetName) | 使用指定的字符集將此 String 編碼爲 byte 序列,並將結果存儲到一個新的 byte 數組中。 |
int indexOf(int ch) | 返回指定字符在此字符串中第一次出現處的索引。 |
int indexOf(int ch, int fromIndex) | 返回在此字符串中第一次出現指定字符處的索引,從指定的索引開始搜索。 |
int indexOf(String str) | 返回指定子字符串在此字符串中第一次出現處的索引。 |
int indexOf(String str, int fromIndex) | 返回指定子字符串在此字符串中第一次出現處的索引,從指定的索引開始。 |
String intern() | 返回字符串對象的規範化表示形式。 |
int lastIndexOf(int ch) | 返回指定字符在此字符串中最後一次出現處的索引。 |
int lastIndexOf(int ch, int fromIndex) | 返回指定字符在此字符串中最後一次出現處的索引,從指定的索引處開始進行反向搜索。 |
int lastIndexOf(String str) | 返回指定子字符串在此字符串中最右邊出現處的索引。 |
int lastIndexOf(String str, int fromIndex) | 返回指定子字符串在此字符串中最後一次出現處的索引,從指定的索引開始反向搜索。 |
int length() | 返回此字符串的長度。 |
boolean matches(String regex) | 告知此字符串是否匹配給定的正則表達式。 |
String replace(char oldChar, char newChar) | 返回一個新的字符串,它是經過用 newChar 替換此字符串中出現的全部 oldChar 獲得的。 |
String replaceAll(String regex, String replacement) | 使用給定的 replacement 替換此字符串全部匹配給定的正則表達式的子字符串。 |
String replaceFirst(String regex, String replacement) | 使用給定的 replacement 替換此字符串匹配給定的正則表達式的第一個子字符串。 |
String[] split(String regex) | 根據給定正則表達式的匹配拆分此字符串。 |
String[] split(String regex, int limit) | 根據匹配給定的正則表達式來拆分此字符串。 |
boolean startsWith(String prefix) | 測試此字符串是否以指定的前綴開始。 |
boolean startsWith(String prefix, int toffset) | 測試此字符串從指定索引開始的子字符串是否以指定前綴開始。 |
String substring(int beginIndex) | 返回一個新的字符串,它是此字符串的一個子字符串。 |
String substring(int beginIndex, int endIndex) | 返回一個新字符串,它是此字符串的一個子字符串。 |
char[] toCharArray() | 將此字符串轉換爲一個新的字符數組。 |
String toLowerCase() | 使用默認語言環境的規則將此 String 中的全部字符都轉換爲小寫。 |
String toUpperCase() | 使用默認語言環境的規則將此 String 中的全部字符都轉換爲大寫。 |
String trim() | 返回字符串的副本,忽略前導空白和尾部空白。 |
因爲String的不可變性致使,字符串變動時效率低下,在以後得JDK版本中出現了StringBuilder和StringBuffer.
類 | 可變性 | 線程安全 |
---|---|---|
String | 不可變 | 安全 |
StringBuffer | 可變 | 安全 |
StringBuilder | 可變 | 非安全 |
這個問題實際上是不嚴謹的,但面試通常會遇到,因此咱們要補充來講明。
類的加載和執行要分開來說: 建立了兩個
- 當加載類時,"abc"被建立並駐留在了字符創常量池中(若是先前加載中沒有建立駐留過)。
- 當執行此句時,由於"abc"對應的String實例已經存在於字符串常量池中,因此JVM會將此實例複製到會在堆(heap)中並返回引用地址。
經過字節碼咱們能夠看到:
源碼:String str = new String("abc")
字節碼:
Code:
0: new #2 // class java/lang/String
3: dup
4: ldc #3 // String abc
6: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)
9: astore_1
10: return
複製代碼
執行時僅(#2)建立了一個對象。
關於這個面試題,能夠看看一個超大牛的回答:rednaxelafx.iteye.com/blog/774673
給你們整理了一些面試文檔和視頻,公衆號回覆:架構師 或 面試視頻
本文優先發佈於微信公衆號:碼上實戰