【JAVA面試集錦】String相關的經典面試題
序言
有關String型別的很經典的面試題很多,面試的時候會由String引入JVM、集合、多執行緒等比較深的問題,進而測試個人的基礎知識是否紮實和學習態度,理應重視,先大概整理些,後續再補充整理吧...
一、String、StringBuilder和StringBuffer的區別
1. String是字串常量,StringBuilder和StringBuffer是字串變數
String物件建立完成之後,如果對其更改,都是重新建立一個String物件,建立的過程是先向字串常量池查詢,如果沒有則先建立該物件,然後把該字串物件新增到字串常量池中(jdk1.6複製的是字串物件例項,jdk1.7則是複製字串物件的例項引用);而StringBuilder和StringBuffer都是可變的;
2. StringBuilder是執行緒不安全的,StringBuffer是執行緒安全的
StringBuffer相關方法添加了執行緒同步關鍵字synchronize關鍵字,故執行緒安全的,但效率低。
二、String為什麼設計成不可變(immutable)
1. 字串常量池的優化需要
字串常量池針對String字串使用的一種優化策略,建立字串物件前,首先檢查字串常量是否已經有該字串(通過equal比較),有直接返回字串在字串常量池的引用,避免重複建立字串而消耗多餘的記憶體空間,如果String為可變的,這種優化策略則無效;
2. 允許String物件快取HashCode
字串的不變性保證了hashcode唯一性,不可變的hashcode可以被快取而不用重新計算,提升了像使用String作為鍵值的hashmap的效率,這也側面反映了hashmap為什麼多數使用String作為鍵值的原因了;
3. 多執行緒使用安全性
字串不可變,所以在多執行緒可以共享一個字串例項,而不需要做額外的執行緒同步;
4. 類載入器需要
類載入器用到字串,不可變性提供了安全性,以便類的正確載入;例如在載入java.sql.Connection類,如果這個值被改成myhacked.Connection,則會對資料庫造成不可知的破壞;
5. 安全性
如果字串是不可變的,則會引起很嚴重的安全問題;例如資料庫的使用者名稱和密碼都是以字串形式傳入獲得資料庫的連線,socket程式設計中,主機名等都是以字串形式傳入,如果字串可變,黑客可以很容易改變字串物件的值,造成安全漏洞。
三、String直接建立物件(String s="abc")和intern()方法的區別
兩者在建立字串物件的時候都會先去字串常量池查詢該物件是否存在,如果沒有,在堆中建立字串物件,並把字串例項引用(jdk1.7+)複製到字串常量池中;大概看上去intern()方法該有的功能String s="abc";都有的,那麼intern存在的意義為何?
測試程式碼 Test.java
String s1 = "ab";
String s2 = "c";
String s3 = "abc";
System.out.println(s3=="ab"+"c"); //true
System.out.println(s3==s1+s2); //false
System.out.println(s3==(s1+s2).intern()); //true
編譯程式碼 Test.class
String s1 = "ab";
String s2 = "c";
String s3 = "abc";
System.out.println(s3 == "abc");
System.out.println(s3 == s1 + s2);
System.out.println(s3 == (s1 + s2).intern());
String s="abc"和intern()方法的區別是一個在編譯期,一個在執行期
四、StringBuilder和"+"號的區別?
1. 拼接字串常量
測試類
6 String s1 = "a" + "b" + "c";
7 String s2 = new StringBuilder().append("a").append("b").append("c").toString();
編譯class
String s1 = "abc";
String s2 = "a" + "b" + "c";
位元組件ByteCode
L0
LINENUMBER 6 L0
LDC "abc"
ASTORE 1
L1
LINENUMBER 7 L1
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
LDC "a"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
LDC "b"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
LDC "c"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 2
使用“+”進行字串常量的拼接在編譯時就已經完成,而使用 StringBuilder 進行字串拼接需要在執行時完成。所以單純的字串常量拼接“+”的效率 應該高於 StringBuilder
2. 拼接字串和引用
測試類
6 String s1 = "a";
7 String s2 = new StringBuilder().append(s1).append("b").append("c").toString();
8 String s3 = s1 + "b" + "c";
編譯class
String s1 = "a";
String s2 = s1 + "b" + "c";
String s3 = s1 + "bc";
位元組碼ByteCode
L0
LINENUMBER 6 L0
LDC "a"
ASTORE 1
L1
LINENUMBER 7 L1
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
LDC "b"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
LDC "c"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 2
L2
LINENUMBER 8 L2
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
LDC "bc"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 3
從位元組碼可以看出“+”拼接的字串引用底層還是使用StringBuilder