String直接賦值與使用new String的區別


在研究String直接賦值與new String的區別之前我們需要先了解java中的字符串常量池的概念

字符串常量池

String類是我們平常項目中使用頻率非常高的一種對象類型,jvm為了提升性能和減少內存開銷,避免字符的重復創建,其維護了一塊特殊的內存空間,即字符串池,當需要使用字符串時,先去字符串池中查看該字符串是否已經存在,如果存在,則可以直接使用,如果不存在,初始化,並將該字符串放入字符創常量池中。

使用String直接賦值

String str = “abc”;可能創建一個或者不創建對象,如果”abc”在字符串池中不存在,會在java字符串池中創建一個String對象(”abc”),然后str指向這個內存地址,無論以后用這種方式創建多少個值為”abc”的字符串對象,始終只有一個內存地址被分配。==判斷的是對象的內存地址,而equals判斷的是對象內容。通過以下代碼測試:
 
String str = "abc";
String str1 = "abc";
String str2 = "abc";
System.out.println(str==str1);//true
System.out.println(str==str2);//true

 

也就是str、str1、str2都是指向同一個內存地址。

使用new String 創建字符串

String str = new String(“abc”);至少會創建一個對象,也有可能創建兩個。因為用到new關鍵字,肯定會在堆中創建一個String對象,如果字符池中已經存在”abc”,則不會在字符串池中創建一個String對象,如果不存在,則會在字符串常量池中也創建一個對象。
 
String str = new String("abc");
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str==str1);//false
System.out.println(str==str2);//false

可以看出來,str、str1、str2指向的是不同的內存地址

        這里解釋一下,對於通過 new 產生一個字符串(假設為 ”china” )時,會先去常量池中查找是否已經有了 ”china” 對象,如果沒有則在常量池中創建一個此字符串對象,然后堆中再創建一個常量池中此 ”china” 對象的拷貝對象。

使用String拼接字符串

項目中除了直接使用=賦值,也會用到字符串拼接,字符串拼接又分為變量拼接和已知字符串拼接
 
String str = "abc";//在常量池中創建abc
String str1 = "abcd";//在常量池中創建abcd
String str2 = str+"d";//拼接字符串,此時會在堆中新建一個abcd的對象,因為str2編譯之前是未知的
String str3 = "abc"+"d";//拼接之后str3還是abcd,所以還是會指向字符串常量池的內存地址
System.out.println(str1==str2);//false
System.out.println(str1==str3);//true

str和str1都是字符串常量所以在編譯期就被確定了!而str2中有個str是引用不是字符串常量所以不會在編譯期確定。

而String是final的!所以在b+"c"的時候實際上是新創建了一個對象,然后在把新創建對象的引用傳給c.

所以在項目中還是不要使用new String去創建字符串,最好使用String直接賦值。

String 有一個intern() 方法,native,用來檢測在String pool是否已經有這個String存在。

 
public String intern()
  返回字符串對象的規范化表示形式。
  一個初始時為空的字符串池,它由類 String 私有地維護。 當調用 intern 方法時,如果池已經包含一個等於此 String 對象的字符串(該對象由 equals(Object) 方法確定),則返回池中的字符串。否則,將此 String 對象添加到池中,並且返回此 String 對象的引用。 它遵循對於任何兩個字符串 s 和 t,當且僅當 s.equals(t) 為 true 時,s.intern() == t.intern() 才為 true。 所有字面值字符串和字符串賦值常量表達式都是內部的。
返回: 一個字符串,內容與此字符串相同,但它保證來自字符串池中。
考慮下面的問題:
public static void main(String[] args) throws Exception {  
        String a =  "b" ;   
        String b =  "b" ;         

        System.out.println( a == b);               //true
        String d = new String( "d" ).intern() ; 
        String c = "d" ;  
        System.out.println( c == d);              //true

        System.out.println("------------------"); 

        String d1 = new String( "d" ) ; 
        String e1=d1.intern();
        String c1 = "d" ;  
        System.out.println( c1 == d1);          //false
        System.out.println( c1 == e1);          //true
        System.out.println( e1 == d1);         //false

        System.out.println("------------------"); 

        String s1=new String("kvill"); 
        String s2=s1.intern(); 
        System.out.println( s1==s2 );         //false
        System.out.println( s1+" "+s2 );     //kvill  kvill
        System.out.println( s2==s1.intern() ); //true

}                  

 

面試題:

String s = new String(“xyz”); 產生幾個對象?

         一個或兩個。如果常量池中原來沒有 ”xyz”, 就是兩個。如果原來的常量池中存在“xyz”時,就是一個。對於基礎類型的變量和常量:變量和引用存儲在棧中,常量存儲在常量池中。

java中String new和直接賦值的區別

    對於字符串:其對象的引用都是存儲在棧中的,如果是編譯期已經創建好(直接用雙引號定義的)的就存儲在常量池中,如果是運行期(new出來的)才能確定的就存儲在堆中。對於equals相等的字符串,在常量池中永遠只有一份,在堆中有多份。
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM