目录
一、简介
- 在java代码中,类型(Class,指的是类本身,而非对象)的加载、连接和初始化过程都是在程序运行期间完成的。
加载:最常见的方式是,将已经存在的class文件(字节码文件)从磁盘上加载到内存中。
连接:简单描述就是,将类与类之间的关系确定下来,对于字节码一些相关的处理(校验、验证等)、类与类之间的符号引用转化成直接引用,也是在此阶段完成。
初始化:我们对于类做处理。
- 提供了更大的可能性,增加了更多的可能性
二、类加载器的深入剖析
负责将.class文件加载到内在中,并为之生成对应的Class对象(磁盘 => 内存)
-
类加载器的组成
- Bootstrap ClassLoader 根类加载器,也被称为引导类加载器,负责Java核心类的加载比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
- Extension ClassLoader 扩展类加载器,负责JRE的扩展目录中jar包的加载。在JDK中JRE的lib目录下ext目录。
- System ClassLoader 系统类加载器,负责在JVM启动时加载来自java命令的class文件(我们自己写的),以及classpath环境变量所指定的jar包和类路径。
-
java虚拟机与程序生命周期
在如下几种情况下,java虚拟机将结束生命周期
- 执行system.exit()方法;
- 程序正常执行结束;
- 程序在执行过程中遇到异常或错误而异常结束终止;
- 由操作系统出现错误而导致java虚拟机进程的终止。
-
类的连接、加载与初始化
加载:查找并加载类的二进制数据文件。
连接:——验证:保证被加载类的正确性(比如语法,防止恶意篡改);
——准备:(还没有对象)为类的静态变量分配内存,并将其初始化为默认值;
该例中,为a分配内存,并初始化为0,因为int的默认值是0.
——解释:把类中的符号引用转换为符号引用(可以理解为:有符号表示的关系 转换为 由指针直接指向内存地址)。
初始化:为类的静态变量赋予正确的初始值(此时执行 a=1 )。
使用和卸载阶段不重要。
使用。
卸载。
-
java程序对类的两种使用方式
- 主动方式(七种)
——创建类的实例(new);
——访问某个类或接口的静态变量(getstatic指令),或者对静态变量进行赋值(putstatic指令);
——调用类的静态方法()invokestatic指令);
——反射(如 Class.forName("com.test.Test"));
——初始化一个类的子类(如 Son类继承Person类,初始化Son时也会对Person进行主动使用);
——java虚拟机启动时被标示为启动类的类(也就是含main方法的类);
——JDK1.7开始提供的动态语言支持(不重要)。
例
当main方法中执行System.out.println(MyChild.str); 时输出:MyParent1 static block hello world, 因为MyChild1并未直接定义str(str由父类直接定义),故 MyChild1中的静态字段不会被初始化。
当main方法中执行System.out.println(MyChild.str2); 时输出:MyParent1 static block welcome MyParent1 static block,因为不仅直接定义了MyChild1,而且MyChild1继承了MyParent1,所以MyParent1 也会被初始化。
另外:当执行System.out.println(MyChild.str)时,MyChild没有被初始化,当虚拟机并未明确规定其是否被加载,可以通过以下手段查看:
可以看到 MyChild已经被加载,相关说明
-XX:+TraceClassLoading 用于追踪类的加载信息并打印出来 -XX:+<option> 表示开启option选项 -XX:-<option> 表示关闭option选项 -XX:<option>=<value> 表示j将option选项值设置为value
- 被动方式
除了以上七种情况,其他适用java类的情况都被看做时对类的被动使用,都不会导致类的初始化(只能确定初始化动作不会产生,但并不意味着不会加载和连接)。
所有的java虚拟机实现必须在每个类或接口被java程序“首次主动使用”时才初始化它们(也就是说初始化只会执行一次)。
-
类的加载
类的加载是指将.class文件中的二进制数据读入内存,将其放在运行时的数据区的放大区内,然后在内存中创建一个java.lang.Class对象(无论一个类创建了多少个实例对象,其在内存中的对应的Class对象只有唯一的一份),用来封装类在放大区内的数据结构。加载
-
加载.class文件的方式
- 从本地系统中直接加载;
- 通过网络下载.class文件;
- 从zip、jar等归档文件中加载.class文件;
- 从专有数据库读取(用的很少);
- 将java源文件动态编译为.class文件。(应用场景:动态代理、servelet、jsp(jsp会转成servelet))