亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何使用new來創建對象

發布時間:2021-10-15 15:20:20 來源:億速云 閱讀:271 作者:iii 欄目:編程語言

本篇內容主要講解“如何使用new來創建對象”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“如何使用new來創建對象”吧!

使用 new 來創建對象

使用 new 來創建對象是最簡單的一種方式了,new 是 Java 中的關鍵字,new  通過為新對象分配內存并返回對該內存的引用來實例化一個類,這個實例化一個類其實就相當于創建了一個對象,因為類也是一種對象;new  也負責調用對象的構造函數,下面是使用 new 來創建對象的代碼

Object obj = new Object();

這段代碼中,我們在堆區域中分配了一塊內存,然后把 obj 對象指向了這塊內存區域。

不知道你有沒有看過 new 的字節碼呢?下面是這段代碼的字節碼

如何使用new來創建對象

在 Java 中,我們認為創建一個對象就是調用其構造方法,所以我們使用 new Object() 構造的對象,其實是調用了 Object 類的無參數  的構造方法。但是通過字節碼我們發現,對象的創建和調用其構造方法是分開的。

字節碼的 new 表示在堆中創建一個對象,并把對象的引用推入棧中。invokespecial 表示調用對象無參數的構造方法。其實,JVM  提供了五種方法調用指令,分別是

  • invokestatic:該指令用于調用靜態方法,即使用 static 關鍵字修飾的方法;

  • invokespecial:該指令用于三種場景:調用實例構造方法,調用私有方法(即 private 關鍵字修飾的方法)和父類方法(即 super  關鍵字調用的方法);

  • invokeinterface:該指令用于調用接口方法,在運行時再確定一個實現此接口的對象;

  • invokevirtual:該指令用于調用虛方法(就是除了上述三種情況之外的方法);

  • invokedynamic:在運行時動態解析出調用點限定符所引用的方法之后,調用該方法;在 JDK 1.7 中提出,主要用于支持 JVM  上的動態腳本語言(如 Groovy,Jython 等)

好了,現在你知道了 new 和 invokespecial 是干啥用的,那么 dup 指令呢?

dup 會復制棧上的最后一個元素,然后再次將其推入棧;因此,如果在棧上有一個對象引用,并且調用了  dup,則現在在棧上有對該對象的兩個引用。看起來有點不知其所以然,所以在求助網上的時候,又發現了 R 大的解釋

如何使用new來創建對象

來源:https://www.zhihu.com/question/52749416

后面的 astore 就會把操作數棧頂的那個引用消耗掉,保存到指定的局部變量去。

如果直接使用 new Object() 沒有創建局部變量的話,請注意一下它的字節碼。

如何使用new來創建對象

看出來細微的差別了嗎?上圖中的 astore_1 竟然變成了 pop,這也就是說,new Object()  沒有保存對象的局部變量,而是直接把它給消耗掉了。嗯,符合預期。

所以這是第一種創建的方式,也就是使用 new 來創建。

使用 newInstance 方法來創建

這個newInstance 方法指的是 class 類中的方法,newInstance 方法會調用無參的構造方法創建對象。

我們可以使用 newInstance 方法創建對象,下面是使用示例代碼

User user = (User)Class.forName("com.cxuan.test.User").newInstance();  // 或者使用  User user = User.class.newInstance();

下面我們分析一下這個字節碼,其實使用第一種方式和第二種方式就差了一個 Class.forName  的字節碼,這是一個靜態方法,應該用的是invokestatic,下面我們驗證一下。

第一種方式的字節碼

如何使用new來創建對象

第二種方式的字節碼

如何使用new來創建對象

可以看到,我們驗證的是正確的。

那么這段字節碼是什么意思呢?

ldc 的意思是把常量池中的引用推入到當前堆棧中,invokestatic 和 invokevirtual 我們上面解釋過了,然后就是  checkcast, 這個字節碼的含義就是進行類型轉換,因為 newInstance 生成的是一個 Object 的對象,所以我們需要把它轉換為我們需要的  User 類型,這個字節碼就是干這個活的。

使用反射來創建對象

使用反射來創建對象其實也是使用了 newInstance 方法,只不過這個方法是 Constructor ,Java  反射中構造器的方法,我們可以通過這種方式來創建一個新的對象。如下代碼所示

Constructor<User> constructor = User.class.getConstructor(); User user = constructor.newInstance();

下面是它的字節碼

如何使用new來創建對象

這里解釋下 iconst_0 ,它的意思就是將 int 值 0 加載到堆棧上,這個相當于是為 getConstructor  方法準備參數分配的字節碼。

為了驗證這個結論,我們從簡優化,看一下其他方法的字節碼

User.class.getDeclaredField("id");

它的字節碼如下:

如何使用new來創建對象

可以看到,第二個 ldc 其實就是 getDeclaredField 中的參數,為 String 類型,所以是用的 ldc,它是將引用推入堆棧。

使用對象克隆來創建對象

這是第四種創建方式,使用 Cloneable 類中的 clone() 方法來創建,它的前提是你需要實現 Cloneable 接口并實現其定義的 clone  方法。用 clone 方法創建對象并不會調用任何構造函數。

如下代碼所示

Constructor<User> constructor = User.class.getConstructor(); User user = constructor.newInstance(); user.setName("cxuan");  User user2 = (User)user.clone(); System.out.println(user2.getName());

輸出 cxuan

它的字節碼如下

如何使用new來創建對象

這個字節碼有些長,但是字節碼的概念和含義我們上面已經介紹過了,最主要的就是推入堆棧,調用對應的實例方法。

對象克隆這塊是面試官非常喜歡考的一個點,我后面會解析一下淺拷貝和深拷貝的區別。

使用反序列化創建對象

當我們使用序列化和反序列化時,JVM 也會幫我們創建一個單獨的對象。在反序列化時,JVM 創建對象不會調用任何構造函數,如下代碼所示

ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("xxx")); out.writeObject(user2); out.close(); //Deserialization ObjectInputStream in = new ObjectInputStream(new FileInputStream("xxx")); User user3 = (User) in.readObject(); in.close(); user3.setName("cxuan003"); System.out.println(user3 + ", hashcode : " + user3.hashCode());

這段反編譯過后的字節碼文件比較長,我這里就先不貼出來了,讀者們可以自己編譯看一下,其實并沒有特別的字節碼指令,大部分我們上面已經提到過了。

到此,相信大家對“如何使用new來創建對象”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

华容县| 吉木萨尔县| 延川县| 武义县| 黑水县| 永善县| 香港| 阳曲县| 新巴尔虎左旗| 安义县| 南通市| 馆陶县| 周至县| 饶河县| 和田县| 云梦县| 清水河县| 浮山县| 龙南县| 探索| 句容市| 中江县| 大厂| 安达市| 铜梁县| 朝阳区| 建宁县| 雷州市| 华坪县| 涪陵区| 翁源县| 宁陵县| 沈丘县| 运城市| 东宁县| 张掖市| 兴业县| 舞阳县| 融水| 永德县| 朝阳县|