1. 程式人生 > >JAVA String類型和原型模式

JAVA String類型和原型模式

語言 fin 相同 案例 裏的 ces pos iter 程序

如上例所述,變量a,b和它們的值10,20都是存在棧裏面,聲明的所以String類型的引用也都是存在棧裏。而字符串abc是存在字符串常量池中,new出來的String對象則是存在堆裏。

String str="abc";
System.out.print(str==str1);//true

上面這行代碼被執行的時候,JVM先到字符串池中查找,看是否已經存在值為”abc”的對象,如果存在,則不再創建新的對象,直接返回已存在對象的引用;如果不存在,則先創建這個對象,然後把它加入到字符串池中,再將它的引用返回。所以這句代碼創建了一個對象

String str1="abc";  
System.out.print(str==str2);//true  

通過上面的解釋這個就清楚了,在執行第二行代碼時,”abc”字符串對象在常量池中已存在,所以直接返回池中已存在的那個字符串對象。

String str2="a"+"b"+"c";

由於常量字符串是在編譯的時候就也被確定的,又因”a”,”b”和”c”都是常量,因此變量str2的值在編譯時就可以確定。這行代碼編譯後的與String str=”abc”;是一樣的,所以這句代碼也是只創建了一個對象,但是這與我們平時好像不太一樣啊?一般使用“+”連接兩個字符串都會產生另一個新的字符對象。下面我們看一下下面這行代碼就明白了:

String str3="c";
String str4="ab"+str3;
System.out.print(str==str4);//false 
String str5="ab";
System.out.print(str==str6);//false

從上面例子我們就可以得出:使用“+”連接的兩個字符串本身就是字面常量字符串時,如果池中存在這樣連接後的字符串,則是不會重新創建對象,而是直接引用池中的字符串對象;如果“+”連接的兩字符串中只要有一個不是字面常量串(即已經定義過的),會產生新的字符串對象(拋去特殊如final定義字符串不提)。
那我們來看一下有new創建字符串時會有什麽不同:

String str7=new String("abc");  

首先、這行代碼究竟創建了幾個String對象呢?答案是2個。由於new String(“abc”)相當於”abc”,一個就是創建出來的放在堆的原實例對象,而另一個就是放在常量池中的 “aaa” 對象,當然這裏的str7本身只是一個引用,放在棧裏,用來指向堆中創建出來的對象。

String str7=new String("abc");  
String str8=new String("abc");  
System.out.print(str7.equals(str8));//true
System.out.print(str7==str8);//false
System.out.print(str==str7);//false

由於str7和str8是連個存在棧裏的引用,他們分別創建了兩個對象”abc”,雖然他們內容相同(str7.equals(str8)==true),但是實際存在物理地址不同,所以str7==str8值為false,同理,str指向常量池中的”abc”,所以str==str7也是false。

關於常量池,是為了避免頻繁的創建和銷毀對象而影響系統性能,其實現了對象的共享。
例如字符串常量池,在編譯階段就把所有的字符串文字放到一個常量池中。
(1)節省內存空間:常量池中所有相同的字符串常量被合並,只占用一個空間。
(2)節省運行時間:比較字符串時,==比equals()快。對於兩個引用變量,只用==判斷引用是否相等,也就可以判斷實際值是否相等。

註意:常量池主要用於存放兩大類常量:字面量(Literal)和符號引用量(Symbolic References),字面量相當於Java語言層面常量的概念,如文本字符串,聲明為final的常量值等,符號引用則屬於編譯原理方面的概念。
所以當然常量池不只是表示字符串常量池,例如一些包裝類都實現了常量池技術

基本類型和基本類型的包裝類。基本類型有:byte、short、char、int、long、boolean。基本類型的包裝類分別是:Byte、Short、Character、Integer、Long、Boolean(註意區分大小寫)。
二者的區別是:基本類型體現在程序中是普通變量,基本類型的包裝類是類,體現在程序中是引用變量。因此二者在內存中的存儲位置不同:基本類型存儲在棧中,而基本類型包裝類存儲在堆中
上邊提到的這些包裝類都實現了常量池技術,另外兩種浮點數類型的包裝類則沒有實現
如下:

        Integer i1=10;
        Integer i2=10;
        Integer i3=new Integer(10);
        Integer i4=new Integer(10);
        System.out.print(i1==i2);//true
        System.out.print(i2==i3);//false
        System.out.print(i3==i4);//false
        Double d1=1.0;
        Double d2=1.0;
        System.out.print(d1==d2);//false

案例分析:
1)i1和i2均是引用類型,在棧中存儲指針,因為Integer是包裝類。由於Integer包裝類實現了常量池技術,因此i1和i2的10均是從常量池中獲取的,均指向同一個地址,因此i1=12。
2)i3和i4均是引用類型,在棧中存儲指針,因為Integer是包裝類。但是由於他們各自都是new出來的,因此不再從常量池尋找數據,而是從堆中各自new一個對象,然後各自保存指向對象的指針,所以i3和i4不相等,因為他們所存指針不同,所指向對象不同。
3)d1和d2均是引用類型,在棧中存儲指針,因為Double是包裝類。但Double包裝類沒有實現常量池技術,因此Doubled1=1.0;相當於Double d1=new Double(1.0);,是從堆new一個對象,d2同理。因此d1和d2存放的指針不同,指向的對象不同,所以不相等。

JAVA String類型和原型模式