java - new + 類別名,一定需要申明一個物件嗎?
巴扎黑
巴扎黑 2017-04-18 10:53:33
0
4
631
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();
他們是一樣的嗎!

巴扎黑
巴扎黑

全部回覆(4)
Ty80

先明確幾個概念,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 的方法區和堆疊區以及堆疊區。

在題主的例子中:

CodeBlock02 code = new CodeBlock02();

code 就是存放在本地變數表的一個引用,它指向堆中的物件實例資料。而這個物件實例數據,就是透過new CodeBlock02() 取到的。

再具體一點:

1. 你写的 CodeBlock02.java 文件存放了 CodeBlock02 类的定义,当 jvm 的类加载器加载这个java文件的时候,将其中的类型定义语句存放在了 jvm 的方法区中。

2. 但是这个时候并没有在堆中生成这个对象的实例,也就是说,这个时候因为没有对象,你并不能调用 CodeBlock02 类的非静态方法。

3. 什么时候获取的对象呢?就是在用 new 关键字执行了本类的构造方法以后 new CodeBlock02() 从这时候开始通过 new 关键字和类的构造器, jvm 在虚拟机的堆区创建了一个 CodeBlock02 类的实例,并返回这个实例的引用,同时你也可以通过这个引用调用它的非静态方法了。

綜上所述,code 就是你用來接收 new 出的實例的的“遙控器”,它指向這個物件在堆區的具體位置。

PHPzhong

你需要理解 java 的引用

CodeBlock02 code = new CodeBlock02();

左邊這個叫做 CodeBlock02 類型的變數

右邊這個叫做 CodeBlock02 類型的物件

你也可以讓這個變數依序指向兩個類型相同的不同物件。

CodeBlock02 code;
CodeBlock02 code1 = new CodeBlock02();
CodeBlock02 code2 = new CodeBlock02();
code = code1;
//code.doSomething(); 相当于 code1.doSomething();
code = code2;
//code.doSomething(); 相当于 code2.doSomething();

你甚至可以讓這個類型的變數指向這個類型的子類別的物件:

MyClass m = new SubMyClass(); //SubMyClass 继承于 MyClass

還可以這樣直接在 new 出來的物件上呼叫方法:

new CodeBlock02().doSomething();
Peter_Zhu

兩個都是聲明對象 樓主問的應該是賦值

如果後面不對這個值繼續操作的話 賦不賦值都是一樣的

new CodeBlock02() // 宣告了之後不賦值,沒有辦法後續對這個物件繼續操作
CodeBlock02 code = new CodeBlock02(); // 把宣告的物件賦值給一個變量,可以進行後續操作

PHPzhong

左邊的是物件的引用變量,右邊的則是在記憶體實際分配的物件。

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板