文档章节

【java基础☞初始化顺序】java继承中的初始化顺序

卯金刀GG
 卯金刀GG
发布于 06/25 14:08
字数 1639
阅读 24
收藏 0

1、初始化顺序:父类的静态变量-->父类的静态代码块-->子类的静态变量-->子类的静态代码快-->父类的非静态变量(父类的非静态代码块)-->父类的构造函数-->子类的非静态变量(子类的非静态代码块)-->子类的构造函数

重点关注:父类的非静态变量(父类的非静态代码块)是同一级的,看哪个部分写在类的最前面谁就先被执行,子类的非静态变量(子类的非静态代码块)也是一样。

package com.test;


public class Test {
    public static void main(String[] args) {
        Child c=new Child();
    }
}
class Parent {
    public static PrintMessage a=new PrintMessage("父类静态成员被初始化");
    private PrintMessage b=new PrintMessage("父类非静态成员被初始化"); 
    static{
        System.out.println("父类的静态代码块被执行");
    }
    {
        System.out.println("父类的非静态代码块被执行");
    }
    public Parent(){
        System.out.println("父类的构造方法被执行");
    }   
}

class Child extends Parent{
    public static PrintMessage a1=new PrintMessage("子类静态成员被初始化");
    private PrintMessage b1=new PrintMessage("子类非静态成员被初始化");    
    
    static {
        System.out.println("子类的静态代码块被执行");
    }
    {
        System.out.println("子类的非静态代码块被执行");
    }
    public Child(){
        System.out.println("子类的构造函数被执行");
    }
}

class PrintMessage{
    public PrintMessage(String mes){
        System.out.println(mes);
    }
}

执行结果:

父类静态成员被初始化
父类的静态代码块被执行
子类静态成员被初始化
子类的静态代码块被执行
父类非静态成员被初始化
父类的非静态代码块被执行
父类的构造方法被执行
子类非静态成员被初始化
子类的非静态代码块被执行
子类的构造函数被执行

 

2、JAVA 类的加载机制

Java类加载分为5个过程,分别为:加载,连接(验证,准备,解析),初始化,使用,卸载。

1. 加载
    加载主要是将.class文件(也可以是zip包)通过二进制字节流读入到JVM中。 在加载阶段,JVM需要完成3件事:
    1)通过classloader在classpath中获取XXX.class文件,将其以二进制流的形式读入内存。
    2)将字节流所代表的静态存储结构转化为方法区的运行时数据结构;
    3)在内存中生成一个该类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

2.连接

    2.1. 验证
    主要确保加载进来的字节流符合JVM规范。验证阶段会完成以下4个阶段的检验动作:
    1)文件格式验证
    2)元数据验证(是否符合Java语言规范)
    3)字节码验证(确定程序语义合法,符合逻辑)
    4)符号引用验证(确保下一步的解析能正常执行)
    2.2. 准备
    准备是连接阶段的第二步,主要为静态变量在方法区分配内存,并设置默认初始值。
    2.3. 解析
    解析是连接阶段的第三步,是虚拟机将常量池内的符号引用替换为直接引用的过程。

3. 初始化

    初始化阶段是类加载过程的最后一步,主要是根据程序中的赋值语句主动为类变量赋值。
    当有继承关系时,先初始化父类再初始化子类,所以创建一个子类时其实内存中存在两个对象实例。
 注:如果类的继承关系过长,单从类初始化角度考虑,这种设计不太可取。原因我想你已经猜到了。
    通常建议的类继承关系最多不超过三层,即父-子-孙。某些特殊的应用场景中可能会加到4层,但就此打住,第4层已经有代码设计上的弊端了。

4. 使用
    程序之间的相互调用。

5. 卸载
    即销毁一个对象,一般情况下中有JVM垃圾回收器完成。代码层面的销毁只是将引用置为null。

通过上面的整体介绍后,再来看Singleton2.getInstance()的执行分析:
    1)类的加载。运行Singleton2.getInstance(),JVM在首次并没有发现Singleton类的相关信息。所以通过classloader将Singleton.class文件加载到内存中。
    2)类的验证。略
    3)类的准备。将Singleton2中的静态资源转化到方法区。value1,value2,singleton在方法区被声明分别初始为0,0,null。
    4)类的解析。略(将常量池内的符号引用替换为直接引用的过程)
    5)类的初始化。执行静态属性的赋值操作。按照顺序先是value1 = 5,value2 = 3,接下来是private static Singleton2 singleton2 = new Singleton2();
这是个创建对象操作,根据 结论1 在执行Singleton2的构造方法之前,先去执行static资源和非static资源。但由于value1,value2已经被初始化过,所以接下来执行的是非static的资源,最后是Singleton2的构造方法:value1++;value2++。
所以Singleton2结果是6和4。

以上除了搞清楚执行顺序外,还有一个重点->结论2:静态资源在类的初始化中只会执行一次。不要与第3个步骤混淆。

有了以上的这个结论,再来看Singleton.getInstance()的执行分析:
    1)类的加载。将Singleton类加载到内存中。
    2)类的验证。略
    3)类的准备。将Singleton2的静态资源转化到方法区。
    4)类的解析。略(将常量池内的符号引用替换为直接引用的过程)
    5)类的初始化。执行静态属性的赋值操作。按照顺序先是private static Singleton singleton = new Singleton(),根据 结论1 和结论2,value1和value2不会在此层执行赋值操作。所以singleton对象中的value1,value2只是在0的基础上进行了++操作。此时singleton对象中的value1=1,value2=1。
然后, public static int value1 = 5; public static int value2 = 3; 这两行代码才是真的执行了赋值操作。所以最后的结果:5和3。
如果执行的是public static int value1; public static int value2;结果又会是多少?结果: 1和1。

 

© 著作权归作者所有

卯金刀GG
粉丝 26
博文 265
码字总数 72868
作品 0
昌平
程序员
私信 提问
从原理来理解继承关系的类初始化和实例化的顺序

就像之前的一个评论.我们学习的是思路. 很多人都知道继承关系的类的初始化和实例化的顺序,但如果忘记了怎么办? 如何找到自己的答案? 又如果遇到的问题是关于泛型的擦除问题,又该如何去分析?...

xpbug
2013/03/03
2.3K
4
Java 语言中的实例初始化块 ( IIB) 详解

在 Java 语言中的类初始化块 文章中我们简单的介绍了下 Java 中的实例初始化块 ( IIB )。不过我觉得介绍的有点简单了,于是,再写一篇文章详细介绍下吧。 Java 语言中,存在三种操作:方法 ...

beves
2018/10/14
12
0
深入理解Java类的初始化顺序

Java类加载机制中最重要的就是程序初始化过程,其中包含了静态资源,非静态资源,父类子类,构造方法之间的执行顺序。这类知识经常会出现在面试题中,如果没有搞清楚其原理,在复杂的开源设计...

郑加威
06/03
34
0
Java和Android ClassLoder对比以及Class加载过程

Java的ClassLoder的父子关系如下:Bootstrap--ExtClassClassLoader---AppClassLoader。 JVM启动时先运行启动类加载器Bottstrap,主要加载Java核心API;然后加载扩展类加载器ExtClassLoder,该...

JasmineBen
2018/05/23
0
0
像Go一样写Java,从Go的特性,讨论一种编程风格。

上篇转帖的blog里面提到了Go的特性,作为编写Java时也可以给自己点编程风格的参考。 下面是提到的改进 下面简单学习和分析一下重点的风格提示,领会Ken和Pike的编程思想: 规范的语法(不需要...

Brin想写程序
2014/03/04
300
0

没有更多内容

加载失败,请刷新页面

加载更多

Giraph源码分析(八)—— 统计每个SuperStep中参与计算的顶点数目

作者|白松 目的:科研中,需要分析在每次迭代过程中参与计算的顶点数目,来进一步优化系统。比如,在SSSP的compute()方法最后一行,都会把当前顶点voteToHalt,即变为InActive状态。所以每次...

数澜科技
44分钟前
1
0
Xss过滤器(Java)

问题 最近旧的系统,遇到Xss安全问题。这个系统采用用的是spring mvc的maven工程。 解决 maven依赖配置 <properties><easapi.version>2.2.0.0</easapi.version></properties><dependenci......

亚林瓜子
57分钟前
6
0
Navicat 快捷键

操作 结果 ctrl+q 打开查询窗口 ctrl+/ 注释sql语句 ctrl+shift +/ 解除注释 ctrl+r 运行查询窗口的sql语句 ctrl+shift+r 只运行选中的sql语句 F6 打开一个mysql命令行窗口 ctrl+l 删除一行 ...

低至一折起
今天
7
0
Set 和 Map

Set 1:基本概念 类数组对象, 内部元素唯一 let set = new Set([1, 2, 3, 2, 1]); console.log(set); // Set(3){ 1, 2, 3 } [...set]; // [1, 2, 3] 接收数组或迭代器对象 ...

凌兮洛
今天
1
0
PyTorch入门笔记一

张量 引入pytorch,生成一个随机的5x3张量 >>> from __future__ import print_function>>> import torch>>> x = torch.rand(5, 3)>>> print(x)tensor([[0.5555, 0.7301, 0.5655],......

仪山湖
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部