zoukankan      html  css  js  c++  java
  • 从Java虚拟机角度分析类的实例化顺序

    1.首先展示一下实例代码(Son.java & Father.java)

    public class Father {
        
        public static int a=10;//父类的静态变量
        static{//父类的静态代码块
            a=20;
        }
        {//父类的构造代码块
            a=30;
        }
        
        public Father() {//父类的构造方法
            a=40;
        }
    }
    public class Son extends Father{
        
        public static int s=10;//子类的静态变量
        public int k=20;//子类的实例变量
        static{//子类的静态代码块
            s=20;
        }
        {//子类的构造代码块
            s=30;
        }
        public Son() {//子类的构造函数
            s=40;
        }
        {//子类的构造代码块
            s=50;
        }
    }

    2.将son.java文件编译为son.class文件,然后使用javap反编译查看Son的字节码指令来分析Son的加载顺序,更利于理解(javap -v -c Son > p.txt)。

    3.执行代码"new Son();"后,分析类的加载顺序。

    下面的static{};为<clinit>函数,son();为<init>函数。

      static {};
        descriptor: ()V
        flags: ACC_STATIC
        Code:
          stack=1, locals=0, args_size=0
             0: bipush        10
             2: putstatic     #11                 // Field s:I--------------------------顺序执行静态变量的赋值
             5: bipush        20
             7: putstatic     #11                 // Field s:I--------------------------顺序执行静态代码块
            10: return
      public packet1020.Son();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=2, locals=1, args_size=1
             0: aload_0
             1: invokespecial #16                 // Method packet1020/Father."<init>":()V--------------------执行父类的<init>函数(顺序不变,第一个)
             4: aload_0
             5: bipush        20
             7: putfield      #18                 // Field k:I------------------------------------------------按顺序收集实例变量赋值
            10: bipush        30
            12: putstatic     #11                 // Field s:I------------------------------------------------按顺序收集构造代码块
            15: bipush        50
            17: putstatic     #11                 // Field s:I------------------------------------------------按顺序收集构造代码块
            20: bipush        40
            22: putstatic     #11                 // Field s:I------------------------------------------------最后执行自己的构造函数代码(顺序不变,最后一个)
            25: return

     开始分析:

    1.触发类的加载,在初始化阶段,先执行父类<clinit>函数,然后执行子类<clinit>函数,按照顺序执行静态变量赋值与静态代码块。

    2.代码中执行了构造函数,所以执行<init>函数。

    结论:

    1.父类中顺序执行静态变量赋值,静态代码块

    2.子类中顺序执行静态变量赋值,静态代码块

    3.父类中顺序执行实例变量赋值,构造代码块

    4.父类构造函数

    5.子类中顺序执行实例变量赋值,构造代码块

    6.子类构造函数

    名字解释:摘抄自周志明老师的《深入理解Java虚拟机:JVM高级特性与最佳实践》

    1.有且只有4中情况下必须对类进行初始化(执行<clinit>函数)中的第三种:当初始化一个类时,先初始化父类。这就是为什么父类的<clinit>函数先于子类的<clinit>函数执行。

    2.<clinit>函数:编译器按照源代码中的顺序自动收集类中的所有静态变量的赋值动作和静态代码块中的语句合并而成的。

    3.<init>函数:最开始先调用父类的<init>函数,然后编译器按照源代码中的顺序自动收集类中的实例变量的赋值操作和构造代码块中的语句合并,然后插入到构造函数方法前面,最后是程序员自己写的构造函数代码。

    构造代码块执行顺序先于构造函数

    <init>(){
      1.调用父类<init>方法
      2.顺序执行实例变量的赋值操作和构造代码块
      3.程序员自己的构造函数方法代码
    }
  • 相关阅读:
    微服务架构技术栈选型手册(万字长文)
    Visual Studio 2013 always switches source control plugin to Git and disconnect TFS
    Visual Studio 2013 always switches source control plugin to Git and disconnect TFS
    MFC对话框中使用CHtmlEditCtrl
    ATL开发 ActiveX控件的 inf文件模板
    ActiveX: 如何用.inf和.ocx文件生成cab文件
    Xslt 1.0中使用Array
    如何分隔两个base64字符串?
    An attempt was made to load a program with an incorrect format
    JQuery 公网 CDN
  • 原文地址:https://www.cnblogs.com/kingofkai/p/9821004.html
Copyright © 2011-2022 走看看