• 类加载之初始化(包括静态代码块讲解)


    开始我们先来看一段代码

    package classLoader;
    
    class a {
        public a() {
            System.out.println("init a");
        }
        
        public void say(){
            System.out.println("say a");
        }
        
        {
            System.out.println("block a");
        }
        
        static {
            System.out.println("static a");
        }    
    }
    
    public class b extends a {
        
        public b() {
            System.out.println("init b");
        }
        
        {
            System.out.println("block b");
        }
        
        public void say(){
            System.out.println("say b");
        }
        
        static {
            System.out.println("static b");
        }        
        
        public static void main(String[] args) {
            System.out.println("主程序开始!");
            a test = new b();  //进行类的初始化
            test.say();
            System.out.println("重新创建对象!");
            test = new b(); 
                
        }
    }

    运行结果:image

    我们可以看出静态代码优先于普通代码快更优先与构造函数。同时静态代码块在对象创建前就运行了静态代码块,总是先运行父类代码再运行子类代码,我们也可以说父类代码先行于子类代码块。而在给test重新赋予一个新的a对象时并没有执行静态代码快。接下来我们来分析出现这些现象的原因。

    首先我们先来聊聊类的初始化


    java虚拟机对于5种情况必须进行初始化。

    1. 使用new关键字实例化对象吗,读取或设置一个静态字段,以及调用一个静态方法
    2. 进行反射调用的时候,如果没有进行初始化先触发其初始化。
    3. 初始化一个类时,发现其父类没有进行初始化,则需要先进性父类的初始化。
    4. 虚拟机启动需要执行一个主类时(包含main()方法的类)。
    5. 使用jdk1.7的动态语言支持时如果一个MethodHandle实例最后的解析结果REF_getstatic,REF_putstatic,REF_invokeStatic的句柄时,并且其没有进行初始化则先出发其初始化

    在准备阶段进行系统要求的初始值赋值。而在初始化阶段执行类构造器<clinit>()方法的过程。。

    <clinit>()所发挥的作用


    <clinit>()是初始化阶段主要执行的代码。根据程序员的要求进行变量的赋值和其他资源的调用。<clinit>()方法会自动收集所有类变量赋值和静态代码块。该方法与构造函数不同,他不需要显式的调用父类构造器。在执行子类的<clinit>()方法时父类的<clinit>()已经执行完毕。也就意味着父类的构造器先行于子类的构造器。所以会先输出父类静态代码块的内容,再输出子类静态代码块的内容。

    注意:<clinit>()方法不是必须的,如果没有静态代码,块也没有变量的赋值。那么其可以不生成<clinit>()方法

    <clinit>()是线程安全的,但如果一个县城的<clinit>()耗时很长会导致多个进程阻塞。也就是说stati代码块应用不当会造成进程阻塞。

    Q&A


    在给test重新赋予一个新的a对象时并没有执行静态代码快的原因?

    该类已经初始化了,不用再进行初始化,故不需要进行初始化,也就不需要执行<clinit>(),自然也就不会输出静态代码的内容。

    静态代码块,普通代码块,构造函数运行顺序?

    由程序运行结果可知:静态代码块>普通代码块>构造函数

    注意;父类代码先行于子类代码,代码进行初始化5种情况的第3种

    人真是奇怪,非得走到最后一步,是不会觉悟的。但是到了最后一步,又觉得太晚了。
  • 相关阅读:
    Android代码宏控制方案 【转】
    android 系统签名【转】
    linux中udev简单的用法-->【转】
    linux中udev简单的用法【转】
    linux udev 机制【转】
    SQL SERVER2008 存储过程、表、视图、函数的权限
    用友u8数据库表结构
    SqlServer 添加用户 添加角色 分配权限
    SP_attach_db 添加数据库文件
    数据库的创建和文件的修改
  • 原文地址:https://www.cnblogs.com/boWatermelon/p/6896690.html
Copyright © 2020-2023  润新知