在Java中,一个对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的。在实例化一个对象时,JVM首先会检查相关类型是否已经加载并初始化,如果没有,则JVM立即进行加载并调用类构造器完成类的初始化。

一个类及其对象初始化的过程

什么时候需要初始化一个类

首次创建某个对象时:

Dog dog = new Dog();

首次访问某个类的静态方法或者静态字段时:

Dog.staticFields;

Java 解释器就会去找类的路径,定位已经编译好的 Dog.class 文件。

获得类的资源

然后 jvm 就会载入 Dog.class,生成一个 class 对象。这个时候如果有静态的方法或者变量,静态初始化动作都会被执行。这个时候要注意啦,静态初始化在程序运行过程中只会在 Class 对象首次加载的时候运行一次。这些资源都会放在 jvm 的方法区。

方法区又叫静态区,跟堆一样,被所有的线程共享。

方法区中包含的都是在整个程序中永远唯一的元素,包含所有的 class 和 static 变量。

初始化对象 Dog dog = new Dog()

  1. 第一次创建 Dog 对象先执行上面的一二步
  2. 在堆上为 Dog 对象分配足够的存储空间,所有属性和方法都被设置成默认值(数字为 0,字符为 null,布尔为 false,而所有引用被设置成 null)
  3. 执行构造函数检查是否有父类,如果有父类会先调用父类的构造函数,这里假设 Dog 没有父类,执行默认值字段的赋值即方法的初始化动作。
  4. 执行构造函数。

有父类情况下的初始化

假设: Dog extends Animal

1.执行第一步,找出 Dog.class 文件,接着在加载过程中发现他有一个基类(通过 extends 关键字),于是先执行 Animal 类的第一二步,加载其静态变量和方法,加载结束之后再加载子类 Dog 的静态变量和方法。
如果 Animal 类还有父类就以此类推,最终的基类叫做根基类。
注意:因为子类的 static 初始化可能会依赖于父类的静态资源,所以要先加载父类的静态资源。

2.接着要 new Dog 对象,先为 Dog 对象分配存储空间 -> 到 Dog 的构造函数 -> 创建默认的属性。这里其构造函数里面的第一行有个隐含的 super(),即父类构造函数,所以这时会跳转到父类 Animal 的构造函数。

Java 会帮我们完成构造函数的补充,Dog 实际隐式的构造函数如下:

Dog() { //创建默认的属性和方法 //调用父类的构造函数super()(可显式写出) //对默认属性和方法分别进行赋值和初始化
}

3、父类 Animal 执行构造函数前也是分配存储空间 -> 到其构造函数 -> 创建默认的属性 -> 发现挖槽我已经没有父类了,这个时候就给它的默认的属性赋值和方法的初始化。

4、接着执行构造函数余下的部分,结束后跳转到子类 Dog 的构造函数。

5、子类 Dog 对默认属性和方法分别进行赋值和初始化,接着完成构造函数接下来的部分。

一、为什么要执行父类 Animal 的构造方法才继续子类 Dog 的属性及方法赋值?

因为子类 Dog 的非静态变量和方法的初始化有可能使用到其父类 Animal 的属性或方法,所以子类构造默认的属性和方法之后不应该进行赋值,而要跳转到父类的构造方法完成父类对象的构造之后,才来对自己的属性和方法进行初始化。

这也是为什么子类的构造函数显示调用父类构造函数 super() 时要强制写在第一行的原因,程序需要跳转到父类构造函数完成父类对象的构造后才能执行子类构造函数的余下部分。

二、为什么对属性和方法初始化之后再执行构造函数其他的部分?

因为构造函数中的显式部分有可能使用到对象的属性和方法。

Tips:其实这种初始化过程都是为了保证后面资源初始化用到的东西前面的已经初始化完毕了。很厉害,膜拜 Java 的父亲们。

说了这么多还是来个例子吧。

这里注意 main 函数也是一个静态资源,执行 Dog 类的 main 函数就是调用 Dog 的静态资源。

实例

//父类Animal
class Animal {
/*8、执行初始化*/  private int i = 9;  protected int j;  /*7、调用构造方法,创建默认属性和方法,完成后发现自己没有父类*/  public Animal() {
/*9、执行构造方法剩下的内容,结束后回到子类构造函数中*/  System.out.println("i = " + i + ", j = " + j);  j = 39;  }  /*2、初始化根基类的静态对象和静态方法*/  private static int x1 = print("static Animal.x1 initialized");  static int print(String s) {  System.out.println(s);  return 47;  }
}  //子类 Dog
public class Dog extends Animal {
/*10、初始化默认的属性和方法*/ private int k = print("Dog.k initialized");  /*6、开始创建对象,即分配存储空间->创建默认的属性和方法。 * 遇到隐式或者显式写出的super()跳转到父类Animal的构造函数。* super()要写在构造函数第一行 */  public Dog() {
/*11、初始化结束执行剩下的语句*/System.out.println("k = " + k);  System.out.println("j = " + j);  }  /*3、初始化子类的静态对象静态方法,当然mian函数也是静态方法*/  private static int x2 = print("static Dog.x2 initialized");/*1、要执行静态main,首先要加载Dog.class文件,加载过程中发现有父类Animal, *所以也要加载Animal.class文件,直至找到根基类,这里就是Animal*/       public static void main(String[] args) {  /*4、前面步骤完成后执行main方法,输出语句*/ System.out.println("Dog constructor");
/*5、遇到new Dog(),调用Dog对象的构造函数*/  Dog dog = new Dog();
/*12、运行main函数余下的部分程序*/            System.out.println("Main Left"); }
}

测试输出结果为:

static Animal.x1 initialized
static Dog.x2 initialized
Dog constructor
i = 9, j = 0
Dog.k initialized
k = 47
j = 39
Main Left

Java 对象初始化的过程介绍相关推荐

  1. Java对象的创建过程:类的初始化与实例化

    一.Java对象创建时机 我们知道,一个对象在可以被使用之前必须要被正确地实例化.在Java代码中,有很多行为可以引起对象的创建,最为直观的一种就是使用new关键字来调用一个类的构造函数显式地创建对象 ...

  2. java实例化类之后如何赋值_深入理解Java对象的创建过程:类的初始化与实例化...

    摘要: 在Java中,一个对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的.在实例化一个对象时,JVM首先会检查相关类型是否已经加载并初始化,如果没有,则JVM立即进行加载并调用类 ...

  3. 深入理解Java对象的创建过程:类的初始化与实例化

    摘要: 在Java中,一个对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的.在实例化一个对象时,JVM首先会检查相关类型是否已经加载并初始化,如果没有,则JVM立即进行加载并调用类 ...

  4. Java对象初始化详解

    在Java中,一个对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的.本文试图对Java如何执行对象的初始化做一个详细深入地介绍(与对象初始化相同,类在被加载之后也是需要初始化的,本 ...

  5. 阿里面试题——Java对象初始化

    Java对象初始化 这是一道阿里巴巴的关于Java对象初始化的面试题,堪称经典,代码很简单(编写格式做了些修改),但是需要面试者对Java中对象初始化有一个透彻的认识,那么通过这道面试题,对我有点启发 ...

  6. Java 对象初始化过程

    例子里总共测试了静态代码块,普通代码块,静态成员变量,普通成员 变量,构造器.分别在基类和派生类里各有一套. public class ClassLog {private static final S ...

  7. java 对象初始化过程_Java——对象初始化顺序使用详解

    一. 代码块的概念 在探究对象初始化顺序之前,我们先通过代码来了解一下代码块的概念. class Test{ public static String str1; //静态字段 public Stri ...

  8. Java对象初始化顺序

    今天我在淘宝Blog阅读了一篇关于java对象实例初始化顺序的文章,讲得挺好的,还严谨地找出了JLS. 觉得Demo代码例子举的不简练,我写了一个Demo代码,狗尾续貂一下 :D 示例代码 packa ...

  9. java 对象初始化_Java对象初始化

    自动初始化(默认值) 一个类的所有基本数据成员都会得到初始化,运行下面的例子可以查看这些默认值: classDefault{booleant;charc;byteb;shorts;inti;longl ...

最新文章

  1. java直接内存为什么快_直接内存与 JVM 源码分析
  2. python第三方库排行-scikit-learn: Python强大的第三方库
  3. 各种友(e)善(xin)数论总集,从入门到绝望2
  4. 【运筹学】表上作业法 ( 最优解判别 | 初始基可行解 | 运费修改可行性方案 | 闭回路法 )
  5. SSD(Single Shot MultiBox Detector):因为数据集中图像通道数不对导致的训练异常
  6. cad线性标注命令_CAD常用标注快捷键和命令
  7. mysql修改工资字段_mysql- 修改字段
  8. 【8.0、9.0c】树形列表 列标题 不对齐的问题及解决方案
  9. 如何用softmax和sigmoid来做多类分类和多标签分类
  10. 苹果硬件技术高级副总裁揭露:自研 M1 太难了
  11. 用Python给对方发个邮箱就可以使对方自动关机,鬼知道你干了什么?
  12. 3.字符串(string)
  13. 网络空间安全复习归纳
  14. 塞班系统微信连接不上服务器,充满情怀的塞班系统:手机QQ、微信将无法登陆使用...
  15. 国产ERP有没有机会击败SAP ?
  16. Sicily 2014 Dairy Queen
  17. 炒股两个指标: M1增速和筹码分布
  18. 查询-SPJ练习3参考答案
  19. 二次元高清无水印壁纸
  20. 大学计算机AI学习初步规划 202204

热门文章

  1. 全网最火的Nacos源码构建,你找不到第二个有我仔细的!!
  2. k8s概念入门之kube-proxy-针对早期(0.4)版本阅读
  3. golang源码分析-调度概述
  4. pip包管理工具-install执行流程简单查看
  5. Java变量和数据类型
  6. 美多商城之用户中心(用户基本信息)
  7. S-BEV:用于天气和光照不变的3-DoF定位的语义鸟瞰视图表示
  8. docker-compose编排最佳实战(多服务)
  9. 用CSS在博客园底部加上蒲公英动态效果的实现方法
  10. 无屏幕和键盘配置树莓派WiFi和SSH