java中String常量的存儲原理


相關題目(運行結果在代碼注釋后面)

1、

package StringTest;

public class test1 {

public static void main(String[] args){
String a = "a1";//“a1”在編譯的時候就能確定,所以編譯的時候,a1被放進了常量池中,同時a指向常量池中的a1對象
String b = "a"+ 1;//a和1這兩個常量都能在編譯時確定,所以他們相加的結果也能確定,因此編譯器檢查常量池中是否有值為a1的String對象,發現有了,因此b也指向常量池中的a1對象
System.out.println(a==b);//==判斷的是a和b是否指向同一個對象,也就是同一塊內存區域
}//true
} 

2、

package StringTest;

public class test2 {
public static void main(String[] args){
String a = "ab";
String bb = "b";
String b = "a"+ bb; //編譯器不能確定為常量
System.out.println(a==b);
}//false
} 

3、

package StringTest;

public class test3 {
public static void main(String[] args){
String a = "ab";
final String bb = "b";
String b = "a"+ bb; //bb加final后是常量,可以在編譯器確定b
System.out.println(a==b);
}//true

} 

4、

package StringTest;

public class test4 {
public static void main(String[] args){
String a = "ab";
final String bb = getBB();
String b = "a"+ bb;//bb是通過函數返回的,雖然知道它是final的,但不知道具體是啥,要到運行期才知道bb的值
System.out.println(a==b);
}//false
private static String getBB(){ return "b"; }
} 

5、

package StringTest;

public class test5 {
private static String a = "ab";
public static void main(String[] args){
String s1 = "a";
String s2 = "b";
String s = s1 + s2;//+的用法
System.out.println(s == a);
System.out.println(s.intern() == a);
//intern的含義(intern()用來返回常量池中的某字符串,如果常量池中已經存在該字符串,則直接返回常量池中該對象的引用,否則,在常量池中加入該對象,然后 返回引用) }//flase true }

6、

package StringTest;

public class test6 {
private static String a = new String("ab");
public static void main(String[] args){
String s1 = "a";
String s2 = "b";
String s = s1 + s2;
System.out.println(s == a);
System.out.println(s.intern() == a);
System.out.println(s.intern() == a.intern());
}//flase false true
} 

詳解

1、String使用private final char value[]來實現字符串的存儲,也就是說String對象創建之后,就不能再修改此對象中存儲的字符串內容,所以說String類型是不可變的(immutable);

2、單獨使用""引號創建的字符串都是常量,編譯期就已經確定存儲到String Pool中;

3、使用new String("")創建的對象會存儲到heap中,是運行期新創建的;

     new創建字符串時首先查看池中是否有相同值的字符串,如果有,則拷貝一份到堆中,然后返回堆中的地址;如果池中沒有,則在堆中創建一份,然后返回堆中的地址

  (注意,此時不需要從堆中復制到池中,否則,將使得堆中的字符串永遠是池中的子集,導致浪費池的空間)

4、使用只包含常量的字符串連接符如"aa" + "aa"創建的也是常量,編譯期就能確定,已經確定存儲到String Pool中;

5、使用包含變量的字符串連接符如"aa" + s1創建的對象是運行期才創建的,存儲在heap中;

6、關於equals和==

(1)對於==,如果作用於基本數據類型的變量(byte,short,char,int,long,float,double,boolean ),則直接比較其存儲的"值"是否相等;如果作用於引用類型的變量(String),則比較的是所指向的對象的地址(即是否指向同一個對象)。

(2)equals方法是基類Object中的方法,因此對於所有的繼承於Object的類都會有該方法。在Object類中,equals方法是用來比較兩個對象的引用是否相等,即是否指向同一個對象。

(3)對於equals方法,注意:equals方法不能作用於基本數據類型的變量。如果沒有對equals方法進行重寫,則比較的是引用類型的變量所指向的對象的地址;而String類對equals方法進行了重寫,用來比較指向的字符串對象所存儲的字符串是否相等。其他的一些類諸如Double,Date,Integer等,都對equals方法進行了重寫用來比較指向的對象所存儲的內容是否相等。

7、String、StringBuffer、StringBuilder的區別

(1)可變與不可變:String是不可變字符串對象,StringBuilder和StringBuffer是可變字符串對象(其內部的字符數組長度可變)。

(2)是否多線程安全:String中的對象是不可變的,也就可以理解為常量,顯然線程安全。StringBuffer 與 StringBuilder 中的方法和功能完全是等價的,只是StringBuffer 中的方法大都采用了synchronized 關鍵字進行修飾,因此是線程安全的,而 StringBuilder 沒有這個修飾,可以被認為是非線程安全的。

(3)String、StringBuilder、StringBuffer三者的執行效率:
StringBuilder > StringBuffer > String 當然這個是相對的,不一定在所有情況下都是這樣。

比如String str = "hello"+ "world"的效率就比 StringBuilder st  = new StringBuilder().append("hello").append("world")要高。因此,這三個類是各有利弊,應當根據不同的情況來進行選擇使用:
當字符串相加操作或者改動較少的情況下,建議使用 String str="hello"這種形式;
當字符串相加操作較多的情況下,建議使用StringBuilder,如果采用了多線程,則使用StringBuffer。


免責聲明!

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



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