引用
前言
java中對象創建的方法主要包括,1,使用new關鍵字,2.使用clone方法,3.反射機制,4.反序列化。其中1,3都會明確的顯式的調用構造函數。2是在內存上對已有對象的影印,所以不會調用構造函數。4是從文件中還原類的對象,也不會調用構造函數。本文將簡要列舉這些對象創建的方法,並做一些簡單的分析總結。
創建對象的方法
調用構造函數
- 代碼如下所示:
public class ConstructorTest { public ConstructorTest() { System.out.println("run in constructor"); } public static void main(String[] args) throws Exception { //使用new構建對象 ConstructorTest t1 = new ConstructorTest(); System.out.println(t1); //使用反射構建對象 Class<?> clazz = Class.forName("org.editice.study.constructor.ConstructorTest"); Constructor<?> cons[] = clazz.getConstructors(); ConstructorTest t2 = (ConstructorTest) cons[0].newInstance(); System.out.println(t2); } }
new表達式方式
- 直接調用函數構造器,實際上由以下兩個步驟完成
-
- 創建空對象,(此時類型已經是正確的),字節碼為new
-
- 調用某個版本的構造器,對應的字節碼是
invokespecial <init>
- 調用某個版本的構造器,對應的字節碼是
- 字節碼如圖:
反射方式
- 反射調用函數構造器,字節碼如下圖所示
不調用構造函數
- 代碼如下所示:
public class InstanceWithoutConstructorTest { public InstanceWithoutConstructorTest() { System.out.println("run in constructor"); } public static void main(String[] args) throws Exception{ //allocateInstance方式 Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); Unsafe us = (Unsafe) f.get(null); InstanceWithoutConstructorTest t1 = (InstanceWithoutConstructorTest) us.allocateInstance(InstanceWithoutConstructorTest.class); System.out.println(t1); //java反序列化方式 ReflectionFactory rf = ReflectionFactory.getReflectionFactory(); Constructor constructor = rf.newConstructorForSerialization(InstanceWithoutConstructorTest.class, Object.class.getConstructor()); InstanceWithoutConstructorTest t2 = (InstanceWithoutConstructorTest) constructor.newInstance(); System.out.println(t2); } }
- 運行結果如下所示:
java反序列化方式
- 在Sun Jdk的實現里,java層面的反射類庫與JVM層面的反射實現相互配合來完成反序列化。java.io.ObjectStreamClass通過跟反射方法/構造器調用類似的機制來獲取所謂的“序列化構造器”,在反序列化的時候調用這個版本的構造器。
- 創建“序列化構造器”時要在繼承鏈里從最具體向最抽象的方向搜索,找到第一個不可序列化的類(沒有實現Serializable接口的類),並找出它的無參構造器來調用。也就是說反序列化的時候並不是完全不調用用戶代碼里面聲明的構造器,只是不調用實現了Serializable的類而已。ps:實際上都是調用了object的無參構造器。
- java的反序列化實際上是調用了基類的構造方法,創建對象也是兩個步驟:
-
- 創建出空對象(此時類型已經是正確的了)
-
- 調用用戶自定義的反序列化方法(readObject,如果有的話)或者調用默認的反序列化方法。
allocateInstance方式
- 其實allocateInstance方式也只是反序列化方式中的一種。這里只是簡單的介紹一下。