Java 对象的创建过程包括类初始化 (JVM 类加载机制) 和类实例化两个阶段.
一, Java 对象创建时机
(1)使用 new 关键字创建对象
(2)反射创建对象
使用 Class 类的 newInstance 方法
Student student2 = (Student)Class.forName("Student 类全限定名").newInstance();
使用 Constructor 类的 newInstance 方法
- Constructor<Student> constructor = Student.class.getConstructor(Integer.class);
- Student stu3 = constructor.newInstance(123);
(3)使用 Clone 方法创建对象(实现 Cloneable 接口)
无论何时我们调用一个对象的 clone 方法, JVM 都会帮我们创建一个新的, 一样的对象, 特别需要说明的是, 用 clone 方法创建对象的过程中并不会调用任何构造函数.
(4)使用 (反) 序列化机制创建对象(实现 Serializable 接口)
当我们反序列化一个对象时, JVM 会给我们创建一个单独的对象, 在此过程中, JVM 并不会调用任何构造函数.
二. Java 对象的创建过程
当一个对象被创建时, 虚拟机就会为其分配内存来存放对象自己的实例变量及其从父类继承过来的实例变量(即使这些从超类继承过来的实例变量有可能被隐藏也会被分配空间).
在为这些实例变量分配内存的同时, 这些实例变量也会被赋予默认值(零值).
主要涉及三种执行对象初始化的结构, 分别是实例变量初始化, 实例代码块初始化, 构造函数初始化.
编译器构造类的构造函数 < init>()(按顺序执行):
父类构造器
实例变量初始化和实例代码块初始化相关代码
本身构造函数
1, 实例变量初始化和实例代码块初始化按照编程顺序来执行, 不允许顺序靠前的实例代码块访问其后面定义的实例变量, 但是可以赋值.
- // 编译错误: 代码块不可以访问其后定义的实例变量
- public class InstanceInitializer {
- {
- j = i;
- }
- private int i = 1;
- private int j;
- }
- // 没问题: 代码块可以赋值其后定义的实例变量
- public class InstanceInitializer {
- {
- j = 1;
- }
- private int i = 1;
- private int j;
- }
2, 每一个 Java 中的对象都至少会有一个构造函数, 如果我们没有显式定义构造函数, 那么它将会有一个默认无参的构造函数.
Java 强制要求所有对象 (Object 是 Java 的顶层对象, 没有超类) 构造函数的第一条语句必须是超类构造函数的调用语句或者是类中定义的其他的构造函数 (super()/this() 必须在第一句, 且不能同时出现). 如果我们既没有调用其他的构造函数, 也没有显式调用超类的构造函数, 那么编译器会为我们自动生成一个对超类构造函数的调用
3, 实例化一个类的对象的过程是一个典型的递归过程.
首先实例化 Object 类, 再依次对以下各类进行实例化, 直到完成对目标类的实例化.
三, 综合实例
- // 父类
- class Foo {
- int i = 1;
- Foo() {
- System.out.println(i);// -----------(1)
- int x = getValue();
- System.out.println(x);// -----------(2)
- }
- {
- i = 2;
- }
- protected int getValue() {
- return i;
- }
- }
- // 子类
- class Bar extends Foo {
- int j = 1;
- Bar() {
- j = 2;
- }
- {
- j = 3;
- }
- @Override
- protected int getValue() {
- return j;
- }
- }
- public class ConstructorExample {
- public static void main(String... args) {
- Bar bar = new Bar();
- System.out.println(bar.getValue());// -----------(3)
- }
- }
- /*
- * Output: 2 0 2
- */
- //Foo 类构造函数的等价变换:
- Foo() {
- i = 1;
- i = 2;
- System.out.println(i);
- int x = getValue();// 在执行 Foo 的构造函数的过程中, 由于 Bar 重载了 Foo 中的 getValue 方法, 所以其调用的是 Bar 的 getValue 方法
- System.out.println(x);
- }
- //Bar 类构造函数的等价变换
- Bar() {
- Foo();
- j = 1;
- j = 3;
- j = 2
- }
参考资料:
深入理解 Java 对象的创建过程: 类的初始化与实例化
来源: https://www.cnblogs.com/hexinwei1/p/9911202.html