JVM学习笔记3-类的加载,连接和初始化

在Java代码中,类型的加载,连接初始化过程都是在程序运行期间完成的

  • 加载:将已存在的.class文件文件从磁盘加载到内存中
  • 连接:将类与类之间的关系确立好,并完成字节码相关的验证,校验,并将符号引用变为直接引用
  • 初始化:对静态变量赋值

优点:
提供了更大的灵活性
增加了更多的可能性


类加载过程

连接的三个步骤
加载
验证
准备
解析
初始化
类实例化
垃圾回收和对象终结

调用一个类的main方法时,其执行步骤如下:

Created with Raphaël 2.2.0 开始 装载类MyTest1了吗? 连接 初始化MyTest 调用MyTest.main() 结束 ClassLoader装载顺利 抛出异常 yes no yes no

1.加载 —查找并加载类的二进制数据

将二进制形式的.class文件读入JVM中

  • 将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区中
  • 在内存中创建一个java.lang.class对象(规范并未说Class对象位于哪里,HotSpot虚拟机将其放在了方法区中)用来封装类在方法区的数据结构
  • 类的加载的最终产品是位于内存中的Class对象
  • Class对象封装了类在方法区内的数据结构,并像Java程序提供了访问方法区内数据结构的接口

加载.class文件的方式

  • 从本地系统中直接加载
  • 通过网络下载.class文件
  • 从zip, jar等归档文件中加载.class文件
  • 从专有数据库中提取.class文件
  • 将Java源文件动态编译为.class文件

2.连接

类被加载后,就进入到连接阶段—就是将已经读入到内存中的类的二进制数据合并到虚拟机的运行时环境中去

连接包括三个步骤:

  • 验证—确保被加载类的正确性(符合JVM规范)
  • 准备—为类的静态变量分配内存,设置默认值,
    在到达初始化之前,类变量都没有初始化为真正的初始值
  • 解析—解析过程就是在类型的常量池中寻找类,接口,字段和方法的符号引用,把这些符号引用替换成直接引用的过程
2.1 验证 – 确保被加载类的正确性(符合JVM规范)
  • 验证内容包括
    • 类文件的结构检测
    • 语义检查
    • 字节码检测
    • 二进制兼容性检查

2.2 准备

为类变量分配内存,设置默认值,但是在到达初始化之前,类变量都没有初始化为真正的初始值

例如: 对与以下Sample类,在准备阶段,将为int类型的静态变量a分配4个字节的内存空间,并赋予默认值0,为long类型的静态变量b分配8个字节的内存空间,并且赋予默认值0
即:int初始化为0,boolean初始化为false

public class Sample{
	private static int a = 1;
	public static long b;
	static{
		b=2;
	}
	...
}
2.3 解析

把类中的符号引用转为直接引用,使用指针的方式指向目标对象内存地址

  • 在类型的常量池中寻找类,接口,字段和方法的符号引用,把这些符号引用替换成直接引用的过程


3.初始化—为类的静态变量赋予正确的初始值

初始化阶段.JVM执行类的初始化语句,为类的静态变量赋予初始值.
在程序中,静态变量的初始化有两种途径:
1). 在静态变量的声明处进行初始化
2). 在静态代码块中进行初始化

例如在以下代码中,静态变量a和b都被显示初始化,而静态变量从没有被显示初始化,它将保持默认值0

public class Sample{
	private static int a = 1;
	public static long b;
	public static long c;
	static{
		b=2;
	}
	...
}

静态变量的声明语句,以及静态代码块都被看做类的初始化语句,JVM会按照初始化语句在类文件的先后顺序来依次执行他们.例如以下Sample类被初始化后,它的静态变量a的取值为4

public class Sample{
  private static int a = 1;
  public static long b;
  static{
  	a = 2;
  }
  static{
  	a = 4;
  }
public static void main(String args[]){
  System.out.println("a="+a);
}
  ...
}

执行结果为

a=4


所有的JVM实现必须在每个类或接口被Java程序首次使用是才初始化他们


  • 类的初始化原则
    • 假如这个类还没有被加载和连接,那么就先进行加载和连接
    • 假如类存在直接父类,并且这个父类还没有被初始化,那就先初始化直接父类
    • 假如类中存在初始化语句,那就依次执行这些初始化语句

  • 类的初始化时机
    只有当程序访问的静态变量或静态方法确实在类或当前接口中定义时,才可以认为是对类或接的主动使用

    • 主动使用(七种重要)
    • 除了上述七种情形,其他使用Java类的方式都被看作是被动使用,不会导致类的初始化
    • JVM初始化一个类时,要求它的所有分类都已经被初始化,但是这条规则并不适用于接口
      • 在初始化一个类时,并不会先初始化它所实现的接口
      • 在初始化一个接口时,并不会先初始化它的父接口

      因此,一个父接口并不会因为它的子接口或者实现类的初始化而初始化,只有当程序首次使用特定接口的静态变量是,才会导致该接口的初始化

调用ClassLoader类的loadClass方法加载一个类,并不是对类的主动使用,不会导致类的初始化



5.类的实例化

  • 为新的对象分配内存
  • 为实例变量赋默认值
  • 为实例变量赋正确的初始值
    java编译器为它编译的每一个类至少生成一个实例初始化方法,在java的class文件中,这个实例初始化方法被称为<init>. 针对源代码中每一个类的构造方法,java编译器都产生一个<init>方法

类的使用方式

  • 创建对象的实例
  • 调用对象的方法

类的使用类型

  • 主动使用
  • 被动使用

JVM学习笔记4-类加载器

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值