类初始化与实例初始化过程分析
类初始化与实例初始化
关于类初始化与实例初始化
当我们在创建一个实例对象时,这个对象的创建是按照怎样的规则被初始化的,或者说其各个属性及代码片段的初始化顺序是怎样的呢?这是面试的一个高频考点,也是作Java程序员的我们起码要掌握的知识。希望这篇文章在这方面能对你有所帮助。
程序分析
首先我们来分析下面的程序将会运行出怎样的结果:
正确答案是:
为什么会运行出这样的结果呢?
类初始化与实例初始化
当一个对象被创建时,实例对象属于哪个类,就会初始化该类,然后再进行这个实例对象的初始化。
对于 Father son1 = new Son(); 我们创建了一个Son的实例对象,首先会进行类Son的初始化,而后进行该实例son1的初始化。
那么类初始化和实例初始化的过程是怎样的呢?
类初始化
-
一个类要创建实例,需要先加载并初始化该类
main() 方法所在的类需要先加载和初始化 - 一个子类要初始化需要先初始化父类
-
一个类的初始化就是执行其 clinit() 方法
① clinit() 方法由类变量显式赋值代码和静态代码块代码组成
② 类变量显式赋值代码和静态代码块代码从上到下顺序执行
③ clinit() 方法只执行一次
实例初始化
-
实例初始化就是执行其 init() 方法
① 有几个构造器就有几个 init() 方法,所以 init() 方法可能重载有多个
② init() 方法由实例变量显式赋值代码和非静态代码块代码、对应构造器代码组成
③ 实例变量显式赋值代码和非静态代码块代码从上到下顺序执行
④ 每次创建实例对象,调用对应构造器,执行的就是对应的 init() 方法
⑤ init() 方法的首行是super() 或super(实参列表),即对应父类的init() 方法每一个类都有 clinit() 和 init() 方法,即类初始化方法和实例初始化方法。它们并非由我们自己编写,而是编译器自动生成的。查看字节码文件可以找到这两个方法的执行记录
回归分析
知道以上几点后,再回到之前的程序中:
对于 Father son1 = new Son() 创建实例的过程如下:
- 父类的初始化 (clinit)
① j = method2() // (5)
② 父类静态代码块 // (2) - 子类的初始化 (clinit)
① j = method2() // (10)
② 子类静态代码块 // (7) - 子类实例初始化 (init)
① 父类实例初始化 super() (最前)
⑴ super()
⑵ i = method1() // (4)
⑶ 父类非静态代码块 // (1)
⑷ 父类构造方法 // (3)
② i = method1() // (9)
③ 子类非静态代码块 // (6)
④ 子类构造方法(最后) // (8)
其中对于 3. 子类实例初始化 和 ① super :
super()是最先执行的,类构造器最后执行,其他实例变量显式赋值代码和非静态代码块代码按照从上到下的顺序依次执行。
接下来,我们再来看一个问题,分析下面这个程序的执行结果
另外
分析以下代码将会运行出怎样的结果
正确答案:
看到结果后与之前的结果进行对比,不难发现第一个(4)变成了(9)。其实不难理解,按照我们之前的问题分析,第 3.①.⑵ 步中的i = method1()方法,被子类Son重写了,所以会执行子类重写的method1()方法。那父类为什么method2执行的结果是(5)呢?行了, 涉及到方法覆盖重写的知识。按照传统博客的点到为止,有关覆写的知识我就不多说了,自己搜去吧…
推荐阅读
-
类初始化与实例初始化过程分析
-
类初始化、实例初始化
-
“面向对象C++”实验二 类与对象定义初始化
-
Java object Initialization (class Instantiation) | 对象的初始化(即类的实例化) 博客分类: Java Foundation javaobject InitializationClass Instantiation对象的初始化类的实例化
-
Java类初始化和实例化中的2个“雷区”
-
Spring中初始化泛型类的方法实例
-
类成员定义时初始化与通过构造函数初始化
-
Java类初始化和实例化中的2个“雷区”
-
Spring中初始化泛型类的方法实例
-
Java类加载初始化的过程及顺序