类的加载、链接和初始化
jvm和类的运行
当调用java命令运行某个java程序时,该命令将会启动一个java虚拟机进程,不管该java程序有多复杂,该程序启动了多少个
线程,他们都处于该java虚拟机进程里。同一个jvm的所有线程、所有变量都处于同一个进程里,都是用jvm进程的内存去。
类的加载
当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过加载、链接、初始化三个步骤来对该类进行初始化。一
般jvm会连续完成这三个步骤,所以把这三个步骤统称为类加载或类初始化。
类加载指的是将类的class文件读到内存,并为之创建一个java.lang.Class对象,也就是说,当程序中使用任何类时,系统都会
为之建立一个java.lang.Class对象。
类的加载由类加载器完成,类加载器通常由jvm提供,这些类加载器也是前面所有程序运行的基础,jvm提供的这些类加载器通常
被称为系统类加载器。除此之外,开发者可以通过集成ClassLoader基类来创建自己的类加载器。
类的连接
当类加载之后,系统为之生成一个Class对象,接着将会进入链接阶段,连接阶段负责吧类的二进制数据合并到jre中。类连接又
分为如下三个阶段。
验证:验证阶段用于检验被加载的类是否有正确的内部结构,并和其他类协调一致。
准备:类准备阶段则负责为类的类变量分配内存,并设置默认初始值。
解析:将类的二进制数据中的符号引用替换成直接引用。
类的初始化
在的初始化阶段,虚拟机负责对类进行初始化,主要就是对类变量进行初始化。
jvm初始化一个类包含如下几个步骤。
1、假如这个类还没有被加载和连接,则程序先加载并连接这个类
2、假如该类的直接父类还没有被初始化,则先初始化其直接父类。
3、假如类中有初始化语句,则系统依次执行这些初始化语句。
类初始化的时机:
1、创建类的实例,不管用什么方式,反射、new
2、调用某个类的静态方法
3、访问某个类或接口的类变量
4、使用反射方式强制创建某个类或接口对应的java.lang.Class对象。Class.forName("com.demo.Person")。
5、初始化某个类的子类。
6、直接使用java.exe命令来运行某个主类。
注意:被final修饰的类变量,即使程序使用该类变量,也不会导致该类的初始化。例如下
class MyTest{
static{
System.out.println("静态代码块");
}
// 使用static final 的类变量赋值
static final String compileConstant = "java"
}
public class CompileConstantTest{
public static void main(Stirng[] args) {
System.out.println(MyTest.compileConstant);
}
}
当使用ClassLoader类的loadClass()方法来加载某个类时,该方法只是加载该类,并不会执行该类的初始化。使用时Class的for
Name()静态方法才会导致强制初始化该类。
类加载器介绍
类加载器负责将.class文件加载到内存中,并为之生成对应的Class对象。
jvm怎么标识是同一个类: (类名、包名、类加载器ClassLoader的实例)
类加载器分类:
Bootstrap ClassLoader:根类加载器。并不是Java.lang.ClassLoader的子类,而是由jvm自身实现的。使用下面方式可以获取根
类加载器所加载的核心类库。运行下面的程序,可以看出我们简单运行一个helloWorld,也会添加加载很多的类。
public class BootStrapTest{
psvm(String[] args) {
// 获取根类加载器所加载的全部Url数组
URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
// 遍历、输出根类加载器加载的全部URL
for (int i = 0; i < urls.length; i++) {
System.out.println(urls[i].toExternalForm());
}
}
}
Extension ClassLoader:扩展类加载器。负责JRE的扩展目录(%JAVA_HOME%/jre/lib/ext)或者由java.ext.dirs系统属性指定
的目录中jar的类。
System ClassLoader:系统类加载器。它负责jvm启动加载来自java命令的classpath选项、java.class.path系统属性,或CLASSP
ATH环境变量所指定的jar包和类路径。程序可以通过ClassLoader的静态方法getSystemClassLoader()来获取系统类加载器。