Java类与接口的静态字段初始化规律总结

JVM加载class字节码的过程可以分为加载、连接(验证、准备,解析)、初始化这三(五)个过程,本文研究的是初始化过程。

  1. 对于静态字段,只有直接定义该字段的类才会被初始化(虽然是通过子类的类名来调用)
    image.png
  • 在编译输出目录下,通过命令行输入java -verbose com.aksr.MyTest1查看类的加载情况,运行结果如下
    com.aksr.MyParent1 加载、初始化
    com.aksr.MyChild1 加载
    image.png
  1. 调用子类静态变量时,会导致父类先初始化,然后子类初始化


    image.png
  • 同上,通过java -verbose com.aksr.MyTest1命令得运行知结果如下
    com.aksr.MyParent1 加载、初始化
    com.aksr.MyChild1 加载、初始化
  1. 对于final修饰的静态常量,如果编译期其值可以确定,则该常量会被放入调用它的方法所在的类的常量池中,此时调用不会引起定义该常量的类的初始化
    image.png
  • 通过javap -c com.aksr.MyTest2反编译字节码文件,如图所示
    ldc助记码表示将int, float或String型常量值从常量池中推送至栈顶,其中"hello world"字符串在MyTest2.class常量池中的符号引用为#4

    image.png

  • 查看类加载的情况,可以发现,MyParent2类并没有被JVM加载(和初始化),即使删除MyParent2.class文件,也可以正常运行MyTest2.class


    image.png
  1. 同理,如果final修饰的常量在编译期不能够确定(如需要进行函数的调用),则会引起类的加载和初始化


    image.png
  2. 对于接口来说,接口内的字段都是public static final修饰的,所以和上面的结论相同,常量a的值在编译期可以确定,所以会被放到MyTest3.class的常量池中,不会引起MyParent3的加载和初始化

    image.png

  • 如果接口内的常量值,编译期不能确定,会引起接口的加载与初始化


    image.png
  1. 子类接口的的初始化不会导致父类接口初始化


    image.png
  • 但是会导致父类的加载


    image.png

总结

使用静态字段不会导致类被加载的情况:该静态字段有final修饰(常量),并且编译期其值可确定
使用静态字段不会导致类被初始化的情况:该静态字段只在父类中定义
子类被初始化前,父类一定会被初始化;子接口初始化,不会导致父接口初始化,但会导致其加载

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 原文链接:Java 类加载机制(阿里面试题)-何时初始化类 - aspirant - 博客园 阅读目录 什么是类加...
    Walter_Hu阅读 989评论 0 8
  • Java类加载与初始化(转载+整合) 这种层面的知识,目前都是从其他的博客或者是书中读来的,自己的认识理解还没有深...
    Muscleape阅读 439评论 0 3
  • 父类 static 块 1 执行 父类 静态成员staticSam1初始化 父类 静态成员staticSam2初始...
    YCix阅读 1,399评论 0 0
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,619评论 1 32
  • 代码编译的结果从本地机器码转变为字节码,是存储格式发展的一小步,确实编译语言发展的一大步。 虚拟机把描述类的数据从...
    胡二囧阅读 1,051评论 0 0

友情链接更多精彩内容