1. 爲什麼 String 類型要用 final 修飾?
爲啥這樣設計呢?, 請帶着這一個疑問看下去,從 String 類的源碼我們可以看出 String 是被 final 修飾的不可繼承類,源碼如下:
Java 語言之父 James Gosling 的回答是:
他會更傾向於使用 final,因爲它能夠緩存結果,當你在傳參時不需要考慮誰會修改它的值;如果是可變類的話,則有可能需要重新拷貝出來一個新值進行傳參,這樣在性能上就會有一定的損失。
那麼從 James Gosling的回答,可以知道他從兩個方面來考慮設計String類型爲 “final 的”
1.安全
當你在調用其他方法時,比如調用一些系統級操作指令之前,可能會有一系列校驗,如果是可變類的話,可能在你校驗過後,它的內部的值又被改變了,這樣有可能會引起嚴重的系統崩潰問題,這是迫使String類設計成不可變類的一個重要原因。
2.高效
以 JVM 中的字符串常量池來舉例,如下兩個變量:
String str1 = "java";
String str2 = "java";
只有字符串是不可變時,我們才能實現字符串常量池,字符串常量池可以爲我們緩存字符串,提高程序的運行效率,如下圖所示:
試想一下如果 String 是可變的,那當 s1 的值修改之後,s2 的值也跟着改變了,這樣就和我們預期的結果不相符了,因此也就沒有辦法實現字符串常量池的功能了。
2. == 和 equals 的區別是什麼?
比較官方的回答是這樣的:
== 對於基本數據類型來說,是用於比較 “值”是否相等的;而對於引用類型來說,是用於比較引用地址是否相同的。
查看源碼我們可以知道 Object 中也有 equals() 方法,源碼如下:
public boolean equals(Object obj) {
return (this == obj);
}
可以看出,Object 中的 equals() 方法其實就是 ==,而 String 重寫了 equals() 方法把它修改成比較兩個字符串的值是否相等。
public boolean equals(Object anObject) {
//先判斷當前引用地址是否相同
if (this == anObject) {
return true;
}
//判斷類型是否爲String
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;
}
3. String 和 StringBuilder、StringBuffer 有什麼區別?
因爲String類型是不可變的,所以在字符串拼接的時候如果使用String的話性能會很低,因此我們就需要使用另一個數據類型StringBuffer,它提供了append和insert方法可用於字符串的拼接,它使用 synchronized 來保證線程安全,如下源碼所示:
因爲它使用了synchronized來保證線程安全,所以性能不是很高,於是在JDK1.5就有了StringBuilder,它同樣提供了append和insert的拼接方法,但它沒有…
4. String 的 intern() 方法有什麼含義?
String常見的創建方式有兩種,直接賦值的方式“Strings1=“Java”;”和“Strings2=newString(“Java”);”的方式,但兩者在JVM的存儲區域卻截然在JDK1.8中,變量s1會先去字符串常量池中找字符串“Java”,如果有相同的字符則直接返回常量句柄,如果沒有此字符串則會先在常量池中創建此字符串,然後再返回常量句柄;而變量s2是直接在堆上創建一個變量,如果調用 intern 方法纔會把此字符串保存到常量池中,如下代碼所示:
5.String 類型在 JVM(Java 虛擬機)中是如何存儲的?編譯器對 String 做了哪些優化?
JDK 1.7 之後把永生代換成的元空間,把字符串常量池從方法區移到了 Java 堆上。
除此之外編譯器還會對 String 字符串做一些優化,例如以下代碼:
雖然 s1 拼接了多個字符串,但對比的結果卻是 true,我們查看Class 文件可以知道JDK優化了
String s1 = "Java";
String s2 = "Java";
//結果爲true
System.out.println(s1 == s2);