資料內(nèi)容:
使用 new 來創(chuàng)建對象
使用 new 來創(chuàng)建對象是最簡單的一種方式了, new 是 Java 中的關(guān)鍵字,new 通過為新對象分配內(nèi)存
并返回對該內(nèi)存的引用來實例化一個類,這個實例化一個類其實就相當于創(chuàng)建了一個對象,因為類也是
一種對象;new 也負責調(diào)用對象的構(gòu)造函數(shù),下面是使用 new 來創(chuàng)建對象的代碼
Object obj = new Object();
這段代碼中,我們在堆區(qū)域中分配了一塊內(nèi)存,然后把 obj 對象指向了這塊內(nèi)存區(qū)域。
不知道你有沒有看過 new 的字節(jié)碼呢?下面是這段代碼的字節(jié)碼
在 Java 中,我們認為創(chuàng)建一個對象就是調(diào)用其構(gòu)造方法,所以我們使用 new Object() 構(gòu)造的對象,其
實是調(diào)用了 Object 類的 無參數(shù) 的構(gòu)造方法。但是通過字節(jié)碼我們發(fā)現(xiàn),對象的創(chuàng)建和調(diào)用其構(gòu)造方法是分開的。
字節(jié)碼的 new 表示在堆中創(chuàng)建一個對象,并把對象的引用推入棧中。 invokespecial 表示調(diào)用對象無
參數(shù)的構(gòu)造方法。其實,JVM 提供了五種方法調(diào)用指令,分別是
invokestatic :該指令用于調(diào)用靜態(tài)方法,即使用 static 關(guān)鍵字修飾的方法;
invokespecial :該指令用于三種場景:調(diào)用實例構(gòu)造方法,調(diào)用私有方法(即 private 關(guān)鍵字修飾
的方法)和父類方法(即 super 關(guān)鍵字調(diào)用的方法);
invokeinterface :該指令用于調(diào)用接口方法,在運行時再確定一個實現(xiàn)此接口的對象;
invokevirtual :該指令用于調(diào)用虛方法(就是除了上述三種情況之外的方法);
invokedynamic :在運行時動態(tài)解析出調(diào)用點限定符所引用的方法之后,調(diào)用該方法;在 JDK 1.7
中提出,主要用于支持 JVM 上的動態(tài)腳本語言(如 Groovy,Jython 等)
好了,現(xiàn)在你知道了 new 和 invokespecial 是干啥用的,那么 dup 指令呢?
dup 會復制棧上的最后一個元素,然后再次將其推入棧;因此,如果在棧上有一個對象引用,并且調(diào)用
了 dup,則現(xiàn)在在棧上有對該對象的兩個引用。看起來有點不知其所以然,所以在求助網(wǎng)上的時候,又
發(fā)現(xiàn)了 R 大的解釋
來源:./images/52749416
后面的 astore 就會把操作數(shù)棧頂?shù)哪莻€引用消耗掉,保存到指定的局部變量去。
如果直接使用 new Object() 沒有創(chuàng)建局部變量的話,請注意一下它的字節(jié)碼。
看出來細微的差別了嗎?上圖中的 astore_1 竟然變成了 pop ,這也就是說,new Object() 沒有保存對
象的局部變量,而是直接把它給消耗掉了。嗯,符合預(yù)期。
所以這是第一種創(chuàng)建的方式,也就是使用 new 來創(chuàng)建。