引用
前言
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方式也只是反序列化方式中的一种。这里只是简单的介绍一下。