天天看點

String類型的幾種存儲方式,是否是線程安全的,兩個字元串相加是否是新的執行個體?(面試題)

String類型

基本資料類型和引用類型的差別主要在于基本資料類型是配置設定在棧上的,而引用類型是配置設定在堆上的。因為String是一個類,是以Java中的字元串String屬于引用資料類型。

String 的兩種建立方法

一、String str = “abc”;

這種方式在堆區開辟空間,“abc”存儲在字元串池中,在棧區建立變量str指向“abc”,當我們再次建立變量String str1 = “abc”時,JVM會到字元串池中尋找“abc”,找到後将引用指派給str1,不會再次開辟空間建立“abc”;

二、String str = new String(“abc”);

這種方式首先在堆區開辟空間存儲“abc”,然後再在堆區開辟空間建立字元串的對象,将“abc”指派給字元串對象,最後将對象的引用指派給str變量,當我們再次建立變量String str1 = “abc”時,JVM會重複執行前面的動作;

String存儲

JDK1.8中JVM把String常量池移入了堆中,針對String對象又做了特殊對待。主要是把heap區域分成了兩塊,一塊是字元串常量池(String constant pool),用于存儲Java字元串常量對象,另一塊用于存儲普通對象及字元串對象。

關于String類:

1.String表示字元串類型,屬于引用資料類型。

2.在java中随便使用雙引号括起來的都是String對象。例如:“abc”, “def”, “hello world”,這是3個對象。

3.java中規定,雙引号括起來的字元串,是不可改變的,final修飾的,自出生到銷毀都是不可改變的。

4.在JDK當中,雙引号括起來的字元串,如:“abc”, "xyz"都是直接存儲在“方法區”的“字元串常量池”當中的。

為什麼SUN公司把字元串存在一個“字元串常量池”當中呢?

因為字元串在實際開發中使用太過頻繁,為了執行效率,是以把字元串放到方法區的字元串常量池當中。

public class Test02 {
    public static void main(String[] args) {
        String s1 = "abc";
        String s2 = "abc";
        String s3 = new String("abc");
        String s4 = new String("abc");

        System.out.println(s1 == s2);  //輸出:true
        System.out.println(s1 == s3);  //輸出:false
        System.out.println(s3 == s4);  //輸出:false
        
		//下面兩行代碼一共建立了幾個對象
        String str1 = new String("hello");
        String str2 = new String("hello");
        //3個,方法區的字元串常量池中一個:"hello",堆記憶體當中new了2個對象,都儲存了"hello"的記憶體位址。
    }
}
           

是否是線程安全的

string内部存儲字元串的char數組以及和char數組相關的資訊都是final的,這就保證了string對象生成的那一刻他在記憶體裡就是不可變的。也就可以了解為常量,線程安全。

Java final的用途?

1、final可以修飾類,方法和變量,

2、final修飾的類,不能被繼承,即它不能擁有自己的子類,

3、final修飾的方法,不能被重寫,

4、final修飾的變量,無論是類屬性、對象屬性、形參還是局部變量,都需要進行初始化操作。

兩個字元串相加是否是新的執行個體

如果有對象參與相加,編譯器沒法處理,結果為新的對象 ,字元串常量直接相加,會先經過編譯器處理;且常量使用過就是一個對象,下次使用不産生新對象。

public static void main(String[] args) {
        String a="1";
        String b="";
      
        String str1=a+b;                //産生新對象
        String str2=a+b;                //産生新對象
        String str3="1"+b;              //有變量參與計算,産生新對象 
        String str4="1"+"";             //編譯器自動優化 <==> String str4="1"; "1"常量字元串已被a引用過
        String str5="1"+"";             //同上  
 
        System.out.println(str1==str2);
        System.out.println(str1==str3);
        System.out.println(str1==str4);
 
        System.out.println(str2==str3);
        System.out.println(str2==str4);
 
        System.out.println(str3==str4);
 
        System.out.println(str4==str5); 

/** 結果顯示為:
              false
              false
              false
              false
              false
              false
              true
              true
*/
    }