java中字符串常量,堆棧的區別和字符串函數intern(),String s=new String(“abc”)中abc在內存的分配


轉自:http://txy821.iteye.com/blog/760957

java.lang.String的intern()方法 
"abc".intern()方法的返回值還是字符串"abc",表面上看起來好像這個方法沒什么用處。但實際上,它做了個小動作: 
檢查字符串池里是否存在"abc"這么一個字符串,如果存在,就返回池里的字符串;如果不存在,該方法會把"abc"添加到字符串池中,然后再返回它的引用。

我們做個測試:

Java代碼   收藏代碼
  1. String str1 = "a";   
  2. String str2 = "bc";   
  3. String str3 = "a"+"bc";   
  4. String str4 = str1+str2;   
  5.      
  6. System.out.println(str3==str4);   
  7. str4 = (str1+str2).intern();   
  8. System.out.println(str3==str4);   

 

輸出的結果將會是: 
false 
true 
JDK的api文檔是這么解釋的: 
======================================================================= 
返回字符串對象的規范化表示形式。 
一個初始時為空的字符串池,它由類 String 私有地維護。 
當調用 intern 方法時,如果池已經包含一個等於此 String 對象的字符串(該對象由 equals(Object) 方法確定),則返回池中的字符串。否則,將此 String 對象添加到池中,並且返回此 String 對象的引用。 
它遵循對於任何兩個字符串 s 和 t,當且僅當 s.equals(t) 為 true 時,s.intern() == t.intern() 才為 true。 
所有字面值字符串和字符串賦值常量表達式都是內部的。字符串字面值在《Java Language Specification》的 §3.10.5 中已定義。 

返回: 
一個字符串,內容與此字符串相同,但它保證來自字符串池中。 
=======================================================================

字符串字面池指的是常量池.

字符串對象的創建方式有兩種

如下:

String s1 = new String("");   //第一種

String s2 = "";               //第二種

第一種始終不會入池的.

第二種要看情況而定(等號右邊如果是常量則入池,非常量則不入池)

例:

String s3 = "a" + "b"; //"a"是常量,"b"是常量,常量+常量=常量,所以會入池.

String s4 = s1 + "b";   //s1是變量,"b"是常量,變量+常量!=常量,所以不會入池.

一旦入池的話,就會先查找池中有無此對象.如果有此對象,則讓對象引用指向此對象;如果無此對象,則先創建此對象,再讓對象引用指向此對象.

例:

String s5 = "abc"; //先在池中查找有無"abc"對象,如果有,則讓s5指向此對象;如果池中無"abc"對象,則在池中創建一個"abc"對象,然后讓s5指向該對象.
補充一下:

看了字節碼后,發現
String str ="a"+"b";
完全等同於
String str="ab";
----------------------
附加一個小實例:
Java代碼   收藏代碼
  1. public class Mud {  
  2. public static String hello(String[] strs, String s2) {  
  3.         strs[0] = "<" + strs[0] + ">";  
  4.         s2.toUpperCase();  
  5. return s2;  
  6.     }  
  7. /** 
  8.      * @param args 
  9.      */  
  10. public static void main(String... args) {  
  11.         String a = new String("t");  
  12.         String[] b = new String[] { "t" };  
  13.         String c = a.intern();  
  14. if (a.equals(b[0])) {  
  15.             System.out.print("1");  
  16.         }  
  17. if (b[0] == c) {  
  18.             System.out.print("2");  
  19.         }  
  20. if (a == c) {  
  21.             System.out.print("3");  
  22.         }  
  23.         a = hello(b, c);  
  24.         System.out.print(a);  
  25.         System.out.print(b[0]);  
  26.         System.out.print(c);  
  27.     }  
  28. }  

 String s=new String(“abc”)中abc在內存的分配

  之前看到好幾篇博客說這樣創建對象時候是先在常量池中創建abc,然后在堆中創建對象s,然后s指向常量池中的abc。其中牛客上有一題如下:

 

 很多解釋都也是這么說的,但是如果說是先在常量池中創建了“abc”在堆里只是引用,那為何下面代碼返回的是false

         String s1=new String("abc");
		String s2="abc";
		System.out.println(s1==s2);

  按照上面解釋,new對象也會在常量池中創建對象,那執行了后第二條的s2也會引用new出來的“abc”,這樣一來應該相等才對啊。

后來看到的解釋說:應該是AC,即是堆和字符串常量池中,當你new String("abc")時,其實會先在字符串常量區生成一個abc的對象,然后new String()時會在堆中分配空間,然后此時會把字符串常量區中abc復制一個給堆中的String,故abc應該在堆中和字符串常量區。

所以:初步認為new出來的對象會在常量池中生成“abc”,然后復制一份到堆中。即s1是指向堆中的”abc“,而s2是指向常量池中的abc。s1.intern()函數是指向s1在字符串常量區生成的“abc”

 

                String s1=new String("abc");
		String s2="abc";
		String s3=s1.intern();
		System.out.println(s1==s3);
		System.out.println(s1==s2);
		System.out.println(s3==s2);                    

  打印結果為:

false
false
true

正好驗證上面的結論。

 棧與堆的區別轉自:http://droidyue.com/blog/2014/12/07/differences-between-stack-and-heap-in-java/ 

Java中的堆和棧的區別

DEC 7TH, 2014

當一個人開始學習Java或者其他編程語言的時候,會接觸到堆和棧,由於一開始沒有明確清晰的說明解釋,很多人會產生很多疑問,什么是堆,什么是棧,堆和棧有什么區別?更糟糕的是,Java中存在棧這樣一個后進先出(Last In First Out)的順序的數據結構,這就是java.util.Stack。這種情況下,不免讓很多人更加費解前面的問題。事實上,堆和棧都是內存中的一部分,有着不同的作用,而且一個程序需要在這片區域上分配內存。眾所周知,所有的Java程序都運行在JVM虛擬機內部,我們這里介紹的自然是JVM(虛擬)內存中的堆和棧。

區別

java中堆和棧的區別自然是面試中的常見問題,下面幾點就是其具體的區別

各司其職

最主要的區別就是棧內存用來存儲局部變量和方法調用。
而堆內存用來存儲Java中的對象。無論是成員變量,局部變量,還是類變量,它們指向的對象都存儲在堆內存中。

獨有還是共享

棧內存歸屬於單個線程,每個線程都會有一個棧內存,其存儲的變量只能在其所屬線程中可見,即棧內存可以理解成線程的私有內存。
而堆內存中的對象對所有線程可見。堆內存中的對象可以被所有線程訪問。

異常錯誤

如果棧內存沒有可用的空間存儲方法調用和局部變量,JVM會拋出java.lang.StackOverFlowError。
而如果是堆內存沒有可用的空間存儲生成的對象,JVM會拋出java.lang.OutOfMemoryError。

空間大小

棧的內存要遠遠小於堆內存,如果你使用遞歸的話,那么你的棧很快就會充滿。如果遞歸沒有及時跳出,很可能發生StackOverFlowError問題。
你可以通過-Xss選項設置棧內存的大小。-Xms選項可以設置堆的開始時的大小,-Xmx選項可以設置堆的最大值。

這就是Java中堆和棧的區別。理解好這個問題的話,可以對你解決開發中的問題,分析堆內存和棧內存使用,甚至性能調優都有幫助。

 


免責聲明!

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



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