引用

前言

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表达式方式

  • 直接调用函数构造器,实际上由以下两个步骤完成

      1. 创建空对象,(此时类型已经是正确的),字节码为new
      1. 调用某个版本的构造器,对应的字节码是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的反序列化实际上是调用了基类的构造方法,创建对象也是两个步骤:
      1. 创建出空对象(此时类型已经是正确的了)
      1. 调用用户自定义的反序列化方法(readObject,如果有的话)或者调用默认的反序列化方法。

allocateInstance方式

  • 其实allocateInstance方式也只是反序列化方式中的一种。这里只是简单的介绍一下。

最新文章

  1. C# Enum Name String Description之间的相互转换
  2. 新冲刺Sprint3(第五天)
  3. C++ exe调用dll文件
  4. 第五天 loadmore
  5. Ecshop文章列表页显示内容摘要
  6. Android VLC播放器二次开发1——程序结构分析
  7. 优秀的Markdown编辑器MarkdownPad2免费版使用全功能
  8. 需要 了解 j2ee 框架
  9. Contest20140906 ProblemC 菲波拉契数制 DP
  10. Oracle的表连接方式
  11. MySQL 5.6中如何定位DDL被阻塞的问题
  12. R语言 画图roc
  13. 自动化CodeReview - ASP.NET Core依赖注入
  14. ubuntu如何实现双屏显示
  15. 【读书笔记】iOS-应用程序剖析
  16. Linux 系统内核的调试
  17. 微信公众号支付安卓和WP支付成功,苹果不能支付!
  18. 【MongoDB安装】MongoDB在centos linux平台安装
  19. ubuntu中安装iso文件
  20. Multivariate Adaptive Regression Splines (MARSplines)

热门文章

  1. SVN与Git的优点差异比较
  2. nginx启动报错
  3. C/C++ 递归
  4. 谈谈mybatis中的#与$的区别
  5. Linux学习--第七天--用户和用户组
  6. Linux 开机自动启动脚本
  7. CentOS7搭建FastDFS V5.11分布式文件系统及Java整合详细过程
  8. 生成对抗网络 Generative Adversarial Networks
  9. 苹果ios开发
  10. qt04 中文显示问题