1. 程式人生 > >String引用資料型別

String引用資料型別

一、String類的第一種方式 (原文地址:https://blog.csdn.net/wangdajiao/article/details/52087302)
1、直接賦值 
例:String str = "hello"; 
直接賦值實際上就是相當於一個匿名物件(“hello”)設定了一個名字(str),String類的匿名物件是由系統自動生成,不在由使用者自己建立,產生了匿名物件就一定在堆記憶體在開闢了一塊堆記憶體空間,並且由一塊棧記憶體指向這塊堆記憶體 
這裡寫圖片描述

2、採用直接賦值的String類物件的記憶體地址完全相同,stra,strb,strc指向同一塊記憶體地址 
例:

public
class StringDemo { public static void main(String[] args) { String stra = "hello" ; String strb = "hello" ; String strc = "hello" ; System.out.println(stra == strb);//true System.out.println(stra == strc);//true System.out.println(strb == strc);//true } }

 

 

這裡寫圖片描述

原因: 
共享設計模式:在JVM底層實際上會有一個物件池(不一定儲存String物件),當代碼之中使用了直接賦值的方式定義了一個String類物件時,會將此字串物件所使用的匿名物件入池儲存,而如果後續還有其他String類物件也採用直接賦值方式,並且設定了同樣的內容的時候,將不會開闢新的堆記憶體空間,而是使用已有的物件進行引用的分配,從而繼續使用。(integer同樣如此)

--如下:

Integer是int的封裝物件,兩個物件==比較的是棧的值
Integer a = new Integer(1);
Integer b = new Integer(1);
a與b存的是Integer的堆中的地址,而不是值
a、b指向堆中的地址顯然不同所以 a==b 為false

int c = 1; int為值型別,

引用型別Integer與值型別int比較顯然比較的是值
因為int在堆中是不開闢記憶體的,他在棧中的值則為他本身的值
所以a==c比較的是他們各自的value, a==c為true

Integer e=1; 這個比較特殊,直接賦值 它有獨立的記憶體,每次賦值時將檢查記憶體中是否有值跟他匹配的,若有則把此記憶體地址付給e,若沒有,開闢新的記憶體

你可以嘗試下面的例子:
Integer t = 1;
Integer t1 = 1;
t==t1 為true,如上所說,此時t與t1指向的是同一塊記憶體

new 一定是開闢新的記憶體,直接賦值則不一定開闢新的記憶體
因為a的引用指向堆,而e指向專門存放他的記憶體,所以他們的記憶體地址不一樣
所以a==e為false

c==e等同於 a==c,一個引用型別一個值型別

二、String類的第二種方式 
1、構造方法 
例:String str = new String("hello")

這裡寫圖片描述 
構造方法一定要使用關鍵字new,一旦使用了關鍵字new就表示要開闢新的堆記憶體空間,如果使用的是構造方法的方式產生String類物件,實際上開闢了兩塊堆記憶體空間(其中匿名物件產生記憶體空間將成為垃圾空間)

public class StringDemo {

    public static void main(String[] args) {
        String stra = new String("hello");
        String strb = "hello";
        System.out.println(stra == strb);//false

}
}

 

 

除了記憶體浪費以外,如果使用了構造方法產生String類物件,其內容不會儲存在物件池之中。因為是使用了關鍵字new開闢的新記憶體

2、手動入池:使用String類定義的public String intern();

public class StringDemo {

    public static void main(String[] args) {
        //使用了構造方法建立物件,而後手動入池
        String stra = new String("hello").intern();
        String strb = "hello";
        System.out.println(stra == strb);//ture

}
}

 


總結 : 
String類兩種例項化的區別 
1、直接賦值:只會開闢一塊堆記憶體空間,並且會自動儲存在物件池之中,以供下次重複使用 
2、構造方法:會開闢兩塊堆記憶體空間,其中有一塊空間將成為垃圾,並且不會自動入池,但是使用者可以使用intern()自動入池


在實際工作中,使用直接賦值產生String類物件

三、字串一旦定義則不可改變 
例:

public class StringDemo {

    public static void main(String[] args) {
        String str = "Hello";
        str = str + "World";
        str += "!!!";
        System.out.println(str);

}
}

 

記憶體分析圖: 
紅框內為垃圾記憶體

因此,字串的內容實際上沒有改變,而對於字串物件內容的改變,是利用了引用關係的變化而實現的,但是每一次的改變都會產生垃圾空間,因此String的內容不要過多頻繁的修改