Java之String理解

 

一、String在內存中的存儲情況

1.Java虛擬機JVM的內存塊及其變量、對象內存空間是怎麼存儲分配的?

1、棧:存放基本數據類型及對象變量的引用,對象本身不存放於棧中而是存放於堆中

             1)、基礎類型 byte (8位)、boolean (1位)、char (16位)、int (32位)、short (16位)、float (32位)、double (64位)、long (64位)

             2)、java代碼作用域中定義一個變量時,則java就在棧中爲這個變量分配內存空間,當該變量退出該作用域時,java會自動釋放該變量所佔的空間

2、堆:new操作符的對象

             1)、new創建的對象和數組

             2)、在堆中分配的內存,由Java虛擬機的自動垃圾回收器來管理

3、靜態域:static定義的靜態成員變量

4、常量池:存放常量

package terry.java.base;

public class StringTest {
     public static void main(String[] args) {
      String a = "hello";
      String b = "hello";
      
      String newA = new String("hello");
      String newB = new String("hello");
      
      System.out.println("****** Testing Object == ******");
      System.out.println("a==b ? :" + (a==b));
      System.out.println("newA==newB ? :" +(newA==newB));
      System.out.println("a==newA ? :" + (a==newA));
      
      System.out.println("***** Testing String Object intern method******");
      System.out.println("a.intern()==b.intern() ? : " + (a.intern()==b.intern()));
      System.out.println("newA.intern()==newB.intern() ? :" + (newA.intern()==newB.intern()));
      System.out.println("a.intern()==newA.intern() ? :" + (a.intern()==newA.intern()));
      System.out.println("a=a.intern() ? :" + (a==a.intern()));
      System.out.println("newA==newA.intern() ? : " + (newA==newA.intern()));
      
      System.out.println("****** Testing String Object equals method******");
      System.out.println("equals() method :" + a.equals(newA));
      
      String c = "hel";
      String d = "lo";
      final String finalc = "hel";
      final String finalgetc = getc();
      
      System.out.println("****** Testing Object splice ******");
      System.out.println("a==\"hel\"+\"lo\" ? :" + (a=="hel"+"lo"));
      System.out.println("a==c+d ? : " + (a==c+d));
      System.out.println("a==c+\"lo\" ? : " + (a==c+"lo"));
      System.out.println("a==finalc+\"lo\" ? :" + (a==finalc+"lo"));
      System.out.println("a==finalgetc+\"lo\" ? :" + (a==finalgetc+"lo"));
      
     }
     private static String getc(){
      return "hel";
     } 
}

********************Testing Object ************************

(1)a、b 創建的 hello 都存在於方法區中的常量池其中的字符串池,故第一條 true 。

(2) newA、newB 創建的 hello 存在於堆中,指向不同的對象,故 false 。

(3)a 創建的 hello 存在於方法區中的常量池其中的字符串池,而 newA 創建的 hello 存在於堆中,故false 。

******************Testing intern method********************

當調用 intern 方法時,如果池已經包含一個等於此 String 對象的字符串(該對象由 equals(Object) 方法確定),則返回池中的字符串。否則,將此 String 對象添加到池中,並且返回此 String 對象的引用。

(1)都指向字符串常量池中的hello,所以true

(2)都指向字符串常量池中的hello,所以true

(3)都指向字符串常量池中的hello,所以true

(4)都指向字符串常量池中的hello,所以true

(5)newA指向堆中的hello對象,newA.intern()指向字符串常量池中的hello,所以爲false;

*********************Testing equals method**********************

equals方法檢測兩個字符串的內容是否相同,而==運算符檢測兩個字符串是否放置在同一個位置上。

(1)a和newA內容相同,所以true;

**********************Testing Object splice**************************

(1) "hel" + "lo"的創建是先進行表達式的字符串連接,然後才進行賦值。賦值的時候會搜索池中是否有 hello 字符串,若有則指向該字符串,若沒有則在池中新增該字符串。顯然 “hel” + "lo" 的創建是用了a 已經創建好的字面量,故 true 。

(2) a == c + d ?; 其實相當於  a== new String(c + d) ?; new String(c + d)  是存放於堆中的,不是字面量。所以 false 。

(3)JVM對於字符串引用,由於在字符串的"+"連接中,有字符串引用存在,而引用的值在程序編譯期是無法確定的,所以c+\"lo\"實際是c在棧中保存的地址+字符串"lo"於常量池中指向的地址 所指向的在堆中新分配的一塊內存空間,所以false

(4)對於final修飾的變量,它在編譯時被解析爲常量值的一個本地拷貝存儲到自己的常量 池中或嵌入到它的字節碼流中,在編譯期就已經確定了內存空間地址,所以此類似於2個字符串常量的+ ,所以true

****** Testing Object == ******
a==b ? :true
newA==newB ? :false
a==newA ? :false
***** Testing String Object intern method******
a.intern()==b.intern() ? : true
newA.intern()==newB.intern() ? :true
a.intern()==newA.intern() ? :true
a==a.intern() ? :true
newA==newA.intern() ? : false
****** Testing String Object equals method******
equals() method :true
****** Testing Object splice ******
a=="hel"+"lo" ? :true
a==c+d ? : false
a==c+"lo" ? : false
a==finalc+"lo" ? :true
a==finalgetc+"lo" ? :false

上述各個變量及引用在JVM分配的內存情況

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章