Tinked in java 4.0 學習總結一

 

成員變量與局部變量:成員變量可以不賦初值直接使用,打印出默認值;局部變量不賦初值使用出錯

保存到什麼位置?(此片段摘自java編程思想 第四版)

程序運行時,我們最好對數據保存到什麼地方做到心中有數。特別要注意的是內存的分配。有六個地方都可
以保存數據:


(1) 寄存器。這是最快的保存區域,因爲它位於和其他所有保存方式不同的地方:處理器內部。然而,寄存
器的數量十分有限,所以寄存器是根據需要由編譯器分配。我們對此沒有直接的控制權,也不可能在自己的
程序裏找到寄存器存在的任何蹤跡。


(2) 堆棧。駐留於常規 RAM(隨機訪問存儲器)區域,但可通過它的“堆棧指針”獲得處理的直接支持。堆
棧指針若向下移,會創建新的內存;若向上移,則會釋放那些內存。這是一種特別快、特別有效的數據保存
方式,僅次於寄存器。創建程序時,Java 編譯器必須準確地知道堆棧內保存的所有數據的“長度”以及“存
在時間”。這是由於它必須生成相應的代碼,以便向上和向下移動指針。這一限制無疑影響了程序的靈活
性,所以儘管有些Java 數據要保存在堆棧裏——特別是對象句柄,但Java 對象並不放到其中。

 

(3) 堆。一種常規用途的內存池(也在 RAM區域),其中保存了Java 對象。和堆棧不同,“內存堆”或
“堆”(Heap)最吸引人的地方在於編譯器不必知道要從堆裏分配多少存儲空間,也不必知道存儲的數據要
在堆裏停留多長的時間。因此,用堆保存數據時會得到更大的靈活性。要求創建一個對象時,只需用new命
令編制相關的代碼即可。執行這些代碼時,會在堆裏自動進行數據的保存。當然,爲達到這種靈活性,必然
會付出一定的代價:在堆裏分配存儲空間時會花掉更長的時間!


(4) 靜態存儲。這兒的“靜態”(Static)是指“位於固定位置”(儘管也在RAM裏)。程序運行期間,靜
態存儲的數據將隨時等候調用。可用static 關鍵字指出一個對象的特定元素是靜態的。但 Java 對象本身永
遠都不會置入靜態存儲空間。


(5) 常數存儲。常數值通常直接置於程序代碼內部。這樣做是安全的,因爲它們永遠都不會改變。有的常數
需要嚴格地保護,所以可考慮將它們置入只讀存儲器(ROM)。

(6) 非RAM 存儲。若數據完全獨立於一個程序之外,則程序不運行時仍可存在,並在程序的控制範圍之外。
其中兩個最主要的例子便是“流式對象”和“固定對象”。對於流式對象,對象會變成字節流,通常會發給
另一臺機器。而對於固定對象,對象保存在磁盤中。即使程序中止運行,它們仍可保持自己的狀態不變。對
於這些類型的數據存儲,一個特別有用的技巧就是它們能存在於其他媒體中。一旦需要,甚至能將它們恢復
成普通的、基於RAM的對象。Java 1.1 提供了對Lightweight persistence 的支持。未來的版本甚至可能提
供更完整的方案。

 

Java內存中的棧: 基本類型變量數據(byte short int long char float double boolean)分配一塊空間,放在棧中;引用變量也放在棧中。定義一個變量 :

int i;                                          //基本類型變量放在棧中
i = 3;                                         // 局部變量的值也放在棧中
String s;                                      //引用型變量放在棧中
s = new String("hello world");                //此時,涉及到堆。new出來的東西放在堆中   
 

String 創建兩種方式分析:

 

String s1 = "hello world";
String s2 = new String ("hello world"); 第一種方式首先在棧中創建一個變量 s1,然後通過引用去字符串常量池中查找是否有"hello world "字符串,如果沒有則將"hello world "字符

串存入字符串常量池,並使 s1 指向此常量。如果有此字符串則直接指向。

第二種方式是用new來新建對象,存放在堆中,每次調用都會新建一個對象。

 

String中相等的比較詳解 “==”和"equals"

“==”是比較兩個對象指向的內存地址是否相等;

"equals"是比較兩個對象的值是否相等。

下面以例子逐一說明:

String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true   編譯器首先處理str1時,根據先前所說,在棧中創建一個值爲str1的引用,然後查找字符串常量中是否有“abc”這個常量;當執行str2時,由

於常量池中已有“abc”字符串,所以將str2直接指向字符串常量“abc”,這樣,str1和str2就是指向同一個對象。

String str1 =new String ("hello");  
String str2 =new String ("hello");  
String str3 = hello              //false
System.out.println(str1==str2); // false   new出來的東西都要在堆中新開闢一個空間。str1 先在棧中建一個變量str1,再在堆中new一個hello;str2也是如此,不過在棧中是另一個變

量,在堆中又開闢一個新的空間。這樣str1和str2指向的就不是同一個對象了。而str3是在常量池中的,當然和堆中的也不相等。


接下來我們看一下字符串連接的相等問題:

String s0="nihao";  
String s1="ni" + "hao";  
System.out.println( s0==s1 );//true
仍然是字符串常量,s1在編譯器就被確定了,他也是常量池“nihao”中的一個引用。

在所有的字符串都是文本常量字符串時,編譯器會在編譯時將它們連接成一個字符串。也就是說在碰到諸如"a"+"b"這樣的代碼時,編譯器會自動合併爲"ab"

 

 

String s0="kvill";  
String s1=new String("kvill");  
String s2="kv" + new String("ill");  
System.out.println( s0==s1 );//false
System.out.println( s0==s2 );//false  
System.out.println( s1==s2 );//false s0仍然是常量池中的引用;s1無法在編譯器確定,所以是運行時在堆中創建的對象“kvill”的引用;s2因爲有後半部分,所以也無法在編譯期確定

,所以也是一個新創建對象“kvill”的引用。

 

 String str1 = "java";
 String str2 = "study";
 String s = str1+str2;
 System.out.print(s=="javastudy");//false……
 

JVM確實會對型如String str1 = "java"; 的String對象放在字符串常量池裏,但是它是在編譯時刻那麼做的,而String s = str1+str2; 是在運行時刻才能知道(我們當然一眼就看穿了,可

是Java必須在運行時才知道的,人腦和電腦的結構不同),也就是說str1+str2是在堆裏創建的, s引用當然不可能指向字符串常量池裏的對象。


String a = "ab";  
String bb = "b";  
String b = "a" + bb;  
System.out.println((a == b)); //result = false  
分析:JVM對於字符串引用,由於在字符串的"+"連接中,有字符串引用存在,而引用的值在程序編譯期是無法確定的,即"a" + bb無法被編譯器優化,只有在程序運行期來動態分配並將連接

後的新地址賦給b。所以上面程序的結果也就爲false。


 

發佈了90 篇原創文章 · 獲贊 4 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章