zoukankan      html  css  js  c++  java
  • 从虚拟机角度理解,为什么静态块函数先于构造函数执行

    作者:DeppWang原文地址

    一、前言

    常常有关于静态块函数、构造函数执行顺序的面试题,如果死记硬背,往往容易混淆。需要从虚拟角度来理解,当真正理解后,其实很简单。

    一个面试题栗子,请输出下面代码的运行结果:

    class StaticSuper {
        static {
            System.out.println("super static block");
        }
    
    StaticSuper() {
        System.out.println("super constructor");
    }
    

    }

    public class StaticTest extends StaticSuper {
    static {
    System.out.println("static block");
    }

    StaticTest() {
        System.out.println("constructor");
    }
    
    public static void main(String[] args) {
        System.out.println("in main");
        StaticTest s = new StaticTest();
    }
    

    }

    执行结果如下:

    super static block
    static block
    in main
    super constructor
    constructor
    

    二、分析

    当执行 StaticTest.main() 时,类加载器加载 StaticTest.class 文件到虚拟机,新建一个与之对应的 Class 对象,如果有类变量,为类变量设置初始值。

    执行 StaticTest.main(),其实是执行 invokestatic 指令,Java 虚拟机规范规定,执行 invokestatic 指令时,需要先初始化类,初始化类时,执行类构造器 <clinit>() 方法, <clinit>() 方法为类变量赋值以及执行静态代码块,虚拟机保证执行 <clinit>() 方法前先执行父类 <clinit>() 方法。

    执行完 <clinit>() 方法后执行 main() 方法

    执行 new 指令时,实例化生成对象,并为实例变量设置初始值(如果没有初始值),再调用实例构造方法 <init>() 为实例变量赋值。

    三、加入构造代码块

    有时候,为了加大难度,里面还会加上构造代码块

    class StaticSuper {
        static {
            System.out.println("super static block");
        }
    
    {
        System.out.println(&quot;super constructor block&quot;);
    }
    
    StaticSuper() {
        System.out.println(&quot;super constructor&quot;);
    }
    

    }

    public class StaticTest extends StaticSuper {
    static {
    System.out.println("static block");
    }

    {
        System.out.println(&quot;constructor block&quot;);
    }
    
    StaticTest() {
        System.out.println(&quot;constructor&quot;);
    }
    
    public static void main(String[] args) {
        System.out.println(&quot;in main&quot;);
        StaticTest s = new StaticTest();
    }
    

    }

    构造代码块可以看成一个公共构造函数,使用任何构造函数前都需要先执行构造代码块。所以执行结果为:

    super static block
    static block
    in main
    super constructor block
    super constructor
    constructor block
    constructor
    

    四、应用

    静态代码块属于类构造函数的范畴,所以常用于设置静态变量。如,Integer 里面的 IntegerCache。

    public final class Integer extends Number implements Comparable<Integer> {
        private static class IntegerCache {
            static final int low = -128;
            static final int high;
            static final Integer cache[];
    
        static {
            // high value may be configured by property
            int h = 127;
            ...
            high = h;
    
            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k &lt; cache.length; k++)
                cache[k] = new Integer(j++);
    
            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high &gt;= 127;
        }
        ...
    }
    

    五、总结

    1、我们将静态代码块看成类构造方法,类构造方法肯定先于实例构造方法执行。

    2、构造代码块可以看成公共构造函数,先于构造函数执行

    这方面的内容可以《深入理解 Java 虚拟机》(第 3 版)- 7.3 类加载的过程,会比看博文理解得更深刻。

  • 相关阅读:
    C#学习笔记
    Visual Studio 快捷键
    java 8 中lambda表达式学习
    Spfa算法
    dijkstra算法
    topSort
    并查集--学习详解
    trie树--详解
    POJ1988 并查集的使用
    Mybatis的一级缓存和二级缓存
  • 原文地址:https://www.cnblogs.com/deppwang/p/12842632.html
Copyright © 2011-2022 走看看