前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >类的加载时机

类的加载时机

作者头像
逍遥壮士
发布2021-03-23 14:40:59
2760
发布2021-03-23 14:40:59
举报
文章被收录于专栏:技术趋势技术趋势

上文:对象的内存是如何布局的?


类的加载主要有三步:加载->连接->初始化。连接过程又分为 验证->准备->解析。

类是通过.java---complier----.class---classloader--Class,然而这个加载又分为以上的7大步骤,那什么时候类开始加载?什么条件必须会加载?什么时候不会被加载?

主动引用:jdk1.7的时候只有5种加载方式,但是jdk1.8及以及类有6种必须对类初始化的条件:

遇到new、getstatic、putstatic或invokestatic必须进行初始化;

代码语言:javascript
复制
//new必须初始化 
SuperClass superClass = new SuperClass();

使用java.lang.reflect包的方法对类型进行反射调用的时候,被调用的必须进行初始化;

代码语言:javascript
复制
//反射必须被初始化 
SuperClass superClass =SuperClass.class.newInstance();

当初始化类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化;

代码语言:javascript
复制
//子类继承父类,并且引用父类变量父类会被初始化 
public class SuperClass {
    static {
        System.out.println("父类SuperClass init!");
    }

    public static int value = 123;
}

public class SubClass extends SuperClass {
    static {
        System.out.println("子类SubClass init!");
    }
}

当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类;

代码语言:javascript
复制
//main方法会被初始化 
public static void main(String[] args) { 
   System.out.println("肯定会被初始化!"); 
}

当使用JDK 7新加入的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果为REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial先进行初始化!

当一个接口中定义了JDK 8新加入的默认方法,有接口实现初始化,则父类必须初始化!

以上这6种方法是虚拟机规定的必须会被加载,也叫主动引用,除此之外所有引用类的方式都不会触发初始化,也叫被动引用。

被动引用:关于不会初始化的场景

1.通过子类引用父类的静态字段,不会导致子类初始化

代码语言:javascript
复制
/**
 *
 * 功能描述: 子类实现父类
 *
 * @param:
 * @return:
 * @auther: csh
 * @date: 2021/3/3 16:18
 */
public class SubClass extends SuperClass {
    static {
        System.out.println("子类SubClass init!");
    }
}
代码语言:javascript
复制
/**
 *
 * 通过子类引用父类的静态字段,不会导致子类初始化
 **/
public class SuperClass {
    static {
        System.out.println("父类SuperClass init!");
    }

    public static int value = 123;
}
代码语言:javascript
复制
/**
 * 非主动使用类字段演示
 **/
public class NotInitialization {
    public static void main(String[] args) {
        System.out.println(SubClass.value);
    }
}

结果:

代码语言:javascript
复制
父类SuperClass init!
123

2.通过数组定义来引用类,不会触发此类的初始化

代码语言:javascript
复制
/**
 * 被动使用类字段演示二:
 * 通过数组定义来引用类,不会触发此类的初始化
 **/
public class NotInitialization {
    public static void main(String[] args) {
        SuperClass[] sca = new SuperClass[10];
    }
}

结果

代码语言:javascript
复制
Process finished with exit code 0

3.常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化

代码语言:javascript
复制
/**
 * 
 * 常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化
 **/
public class ConstClass {
    static {
        System.out.println("ConstClass init!");
    }

    public static final String HELLOWORLD = "hello world";
}

结果:

代码语言:javascript
复制
hello world

接口类的加载

接口类加载与类大致相同,区别如下:

接口不要求父类全部初始化完毕;

接口不能使用static{}代码块;

最后

类的加载时机分为7个阶段,每个阶段都有详细的工作,当然除了加载和卸载其它阶段可能存在并行,而非顺序执行。这里只是简要介绍加载的相关引用问题,关于类加载器,再详细深入。

参考

https://segmentfault.com/a/1190000022716846

https://juejin.cn/post/6844903733952774152

http://www.mamicode.com/info-detail-570611.html

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-03-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 技术趋势 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档