【java笔记】创建对象的五种方式
一般来说有以下五种方式来创建java对象
- new关键字
- Class.newInstance
- Constructor.newInstance
- Clone方法
- 反序列化
1、new关键字
这是我们最常见的也是最简单的创建对象的方式,通过这种方式我们还可以调用任意的构造器(无参的和有参的)。
1 | public class Main { |
2、Class.newInstance
这是我们运用反射创建对象时最常用的方法。
1 | public class Main { |
3、Constructor.newInstance
先通过类对象获得Constructor,再通过constructor的newInstance方法来获得对象。具体可以参考这篇博客。
4、Clone
无论何时我们调用一个对象的clone方法,JVM就会创建一个新的对象,将前面的对象的内容全部拷贝进去,用clone方法创建对象并不会调用任何构造函数。 要使用clone方法,我们必须先实现Cloneable接口并复写Object的clone方法(因为Object的这个方法是protected的,你若不复写,外部也调用不了)。
1 | public class Person implements Cloneable { |
输出结果:
1 | Person{name='fsx', age=18} |
完成了内容的克隆,但是可以发现是个全新的对象。
5、反序列化
当我们序列化和反序列化一个对象,JVM会给我们创建一个单独的对象,在反序列化时,JVM创建对象并不会调用任何构造函数。
为了反序列化一个对象,我们需要让我们的类实现Serializable接口。
1 | public class Main { |
输出:
1 | Person{name='fsx', age=18} |
备注:JDK序列化、反序列化特别特别耗内存。据测试单单一个如上的Person对象的反序列化,2M的JVM内存都还不够…
5种方式对是否调用了构造器的总结
这其实又可以衍生出一个面试题:Java创建实例对象是不是必须要通过构造函数?
针对上面5种方式是否调用了构造函数,绘制表格如下:
| 创建对象方式 | 是否调用了构造器 |
|---|---|
| new关键字 | 是 |
| Class.newInstance | 是 |
| Constructor.newInstance | 是 |
| Clone | 否 |
| 反序列化 | 否 |
因此上面问题的答案很明显了:Java创建实例对象,并不一定必须要调用构造器的。
备注:还有一个库
Objenesis,它也能不使用构造器来创建一个实例。Spring的ObjenesisCglibAopProxy就是依赖于Objenesis这个库的~
附:关于两种newInstance方法的区别?
- Class类位于java的lang包中,而Constructor是java反射机制的一部分
- Class类的
newInstance只能触发无参数的构造方法创建对象,而构造器类的newInstance能触发有参数或者任意参数的构造方法来创建对象。 - Class类的newInstance需要其构造方法是public的或者对调用方法可见的,而构造器类的newInstance可以在特定环境下调用私有构造方法来创建对象。
- Class类的newInstance抛出类构造函数的异常,而构造器类的newInstance包装了一个
InvocationTargetException异常。
说明:Class类本质上调用了反射包
Constructor中无参数的newInstance方法,捕获了InvocationTargetException,将构造器本身的异常抛出


