public class CodeBlock02
{
{
System.out.println("第一代码块");
}
public CodeBlock02()
{
System.out.println("构造方法");
}
{
System.out.println("第二构造块");
}
public static void main(String[] args)
{
new CodeBlock02();
new CodeBlock02();
new CodeBlock02();
}
}
在這裏, new CodeBlock02()
; 或者換成 CodeBlock02 code = new CodeBlock02();
他們是一樣的嗎!
先明確幾個概念,java程式碼是跑在jvm中的,而jvm的記憶體區域被劃分為這麼幾個模組:
程式計數器(Program Counter Register):程式計數器是一個比較小的記憶體區域,用來指示目前執行緒所執行的字節碼執行到了第幾行,可以理解為是目前執行緒的行號指示器。字節碼解釋器在運作時,會透過改變這個計數器的值來取下一條語句指令。
虛擬機棧(JVM Stack):一個執行緒的每個方法在執行的同時,都會建立一個堆疊幀(Statck Frame),在堆疊幀中儲存的有局部變數表、操作站、動態連結、方法出口等,當方法被呼叫時,棧幀在JVM棧中入棧,當方法執行完成時,棧幀出棧。
本地方法棧(Native Method Statck):本地方法棧在作用,運行機制,異常類型等方面都與虛擬機棧相同,唯一的區別是:虛擬機棧是執行Java方法的,而本地方法堆疊是用來執行native方法的,在許多虛擬機器中(如Sun的JDK預設的HotSpot虛擬機器),會將本地方法堆疊與虛擬機器堆疊一起使用。
堆區(Heap):堆區是理解Java GC機制最重要的區域,沒有之一。在JVM所管理的記憶體中,堆區是最大的一塊,堆區也是Java GC機制所管理的主要記憶體區域,堆區由所有執行緒共享,在虛擬機器啟動時建立。堆區的存在是為了儲存物件實例,原則上講,所有的物件都在堆區上分配記憶體(不過現代技術裡,也不是這麼絕對的,也有棧上直接分配的)。
方法區(Method Area):(也稱為永久代),方法區是各個執行緒共享的區域,用於儲存已經被虛擬機載入的類別資訊(即載入類別時需要載入的信息,包括版本、field、方法、介面等資訊)、final常數、靜態變數、編譯器即時編譯的程式碼等。
直接內存(Direct Memory):直接內存並不是JVM管理的內存,可以這樣理解,直接內存,就是JVM以外的機器內存,比如,你有4G的內存,JVM佔用了1G,則其餘的3G就是直接內存,JDK中有一種基於通道(Channel)和緩衝區(Buffer)的內存分配方式,將由C語言實現的native函數庫分配在直接內存中,用存儲在JVM堆中的DirectByteBuffer來引用。由於直接記憶體收到本機器記憶體的限制,所以也可能出現OutOfMemoryError的異常。
明白這幾個基本概念以後再來看看題主疑惑的地方。其實題主疑惑的是在java中,物件的引用是個什麼東西,它們和物件的實例化過程有什麼關係。
別急我們先來分析下java中一個引用是怎麼實現的:
一個Java的引用存取涉及到3個記憶體區域:JVM棧,堆,方法區。
以最簡單的本地變數引用:Object obj = new Object()為例:
Object obj表示一個本地引用,儲存在JVM棧的本地變數表中,表示一個reference類型資料;
new Object()作為實例物件資料儲存在堆中;
堆中也記錄了Object類別的類型資訊(介面、方法、field、物件類型等)的位址,這些位址所執行的資料儲存在方法區中;
具體的實作方式有很多種,句柄是其中一種,關係如圖所示。
看到這裡應該就明白了。類別本身的信息,類別實例數據,以及指向物件的引用資訊分別放在 java 的方法區和堆疊區以及堆疊區。
在題主的例子中:
code 就是存放在本地變數表的一個引用,它指向堆中的物件實例資料。而這個物件實例數據,就是透過
new CodeBlock02()
取到的。再具體一點:
綜上所述,code 就是你用來接收 new 出的實例的的“遙控器”,它指向這個物件在堆區的具體位置。
你需要理解 java 的引用
CodeBlock02 code = new CodeBlock02();
左邊這個叫做 CodeBlock02 類型的變數。
右邊這個叫做 CodeBlock02 類型的物件。
你也可以讓這個變數依序指向兩個類型相同的不同物件。
你甚至可以讓這個類型的變數指向這個類型的子類別的物件:
還可以這樣直接在 new 出來的物件上呼叫方法:
兩個都是聲明對象 樓主問的應該是賦值
如果後面不對這個值繼續操作的話 賦不賦值都是一樣的
new CodeBlock02() // 宣告了之後不賦值,沒有辦法後續對這個物件繼續操作
CodeBlock02 code = new CodeBlock02(); // 把宣告的物件賦值給一個變量,可以進行後續操作
左邊的是物件的引用變量,右邊的則是在記憶體實際分配的物件。