JVM之类的加载+连接+初始化及反编译

1、 JVM

  • Java Virtual Machine(Java虚拟机),JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
  • 引入Java虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。

2、追踪类的加载信息

  • 【-XX:+TraceClassLoading】(-XX:-表示关闭option选项)
  • JVM在当前启动环境下加载类的顺序在这里插入图片描述
    • 应用-》运行
      在这里插入图片描述
    • 启动类-》父类-》主类
      在这里插入图片描述

3、类的加载方式

  • 类的加载、连接(验证、准备、解析)、初始化都是在运行时完成的
    • 加载时:加载字节码【把二进制的java读入JVM】,并在内存中创建Class对象[唯一]【Class对象封装类在方法区的数据结构,并提供访问方法去内数据结构的接口】
    • 准备:为类的静态变量【类变量】分配内存,并初始化为默认值
    • 解析阶段:把类中的符号引用(类/方法/字段名)转为直接(内存)引用
    • 初始化:为类的静态变量赋(正确)值、执行static

被动

  • 除主动外就是被动

主动

  • 首次主动加载才会被初始化

1)new

  • 普通类直接创建实例
    加载过程:
    1)连接时(准备)a=0
    2)初始化时a=3、再加载静态代码块a=4
    3)主函数创建实例,加载代码块a=9,加载构造函数a=18
    在这里插入图片描述
  • 创建子类的实例
    当一个类在初始化时,要求其父类都已经被初始化完毕。
    加载过程:
    1)连接时(准备)a=0,c=0
    2)初始化时a=3、c=3、再加载静态代码块a=4、c=6
    3)创建子类实例,先加载父类代码块a=9、父类构造函数a=18、再加载子类代码块c=11、子类构造函数c=33
    在这里插入图片描述

2)访问类的静态变量/赋值、调用类的静态方法

  • 直接访问普通类的静态变量
    加载过程:
    1)连接时(准备)a=0
    2)初始化时a=3,加载静态代码块a=4
    在这里插入图片描述
  • 调用普通类的静态方法,同上初始化+执行调用方法
    在这里插入图片描述

3)反射

  • 1、含main()类
    在这里插入图片描述

  • 2、普通类
    在这里插入图片描述

  • 3、子类
    在这里插入图片描述

4)初始化一个类的子类

  • 子类调用父类的静态方法,父类初始化,子类并不会被初始化
    在这里插入图片描述
  • 子类调用自己的静态变量才会被初始化
    在这里插入图片描述

5)JVM启动时被标记为启动类的类

在这里插入图片描述

6)MethodHandle【空】

4、测试例子

实例在最前面

加载过程:
1)连接时(准备)创建实例、a=0
2)初始化时加载代码块a=5、加载构造函数a=10,进行初始化赋值a=3、并加载静态代码块a=4
在这里插入图片描述

主函数再创建一个实例:

在这里插入图片描述

创建实例放声明和静态代码块中间

加载过程:
1)连接时(准备)a=0、创建实例
2)初始化时a=3;加载代码块a=8,加载构造函数a=16,加载静态代码块a=17
在这里插入图片描述
加载过程:
1)连接时(准备)a=0,创建实例
2)初始化时a=3,加载静态代码块a=4,加载代码块a=9,加载构造函数a=18
在这里插入图片描述

5、常量与类的初始化

1)编译期能确定常量

  • 在编译阶段会存入调用这个常量的方法的类的常量池中
  • 本质上,调用类,并没有直接引用到定义类的常量,因此,不会初始化定义常量的类
  • 即:A中aa存放到testAB的常量池中

    示例

    在这里插入图片描述

    测试 -------删除A的字节码

在这里插入图片描述

反编译:

  • 补充:还有iconst_0,iconst_m1(minus1/-1)
    在这里插入图片描述
    在这里插入图片描述

常量aa=100时,变bipush

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 另:反编译的用法:
    在这里插入图片描述

2)当常量值在运行期才能确定时

在这里插入图片描述

  • 删除定义常量的类的字节码文件
    在这里插入图片描述

证明:当一个常量的值在编译期无法确定运行期才能确定时,它不会被放到调用此常量的类的常量池中,而是主动使用此常量被定义的类(定义此常量的类会被初始化)

6、数组与类的初始化

  • 数组的类型是JVM在运行期动态生成的,表示为[L…
  • 动态生成的类型,其父类就是Object,故A没有初始化
    在这里插入图片描述

在这里插入图片描述

7、接口与初始化

  • ps:接口默认final
  • 当一个接口在初始化的时候,父接口不一定被初始化
  • 只有当真正使用父接口时,才会被初始化

7.1)引用子接口常量【未】

子接口和父接口都没有被初始化,子接口常量被放入调用该常量的类的常量池中
1)
在这里插入图片描述
2)子接口和父接口都删掉在这里插入图片描述

7.2)引用父接口常量【未】

1)
在这里插入图片描述
2)删除子接口字节码
在这里插入图片描述

7.3)父接口中常量值不确定时,引用父接口常量【子、父接口皆初始化】

1)删除父接口
在这里插入图片描述
2)删除子接口
在这里插入图片描述

7.4)父接口中常量值不确定时,引用子接口常量【未】

1)
删除父接口
在这里插入图片描述
2)删除子接口
在这里插入图片描述

7.5)子、父接口中常量值不确定时,引用子接口常量【子、父初始化】

1)删除父接口
在这里插入图片描述
2、删除子接口
在这里插入图片描述

7.6)子、父接口中常量值不确定时,引用父接口常量【子、父初始化】

。。。

7.7)子接口中常量值不确定时,引用父接口常量【父未初始化】

在这里插入图片描述

7.8)子接口中常量值不确定时,引用子接口常量【父初始化】

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值