目录
启动类加载器(Bootstrap Class Loader)
扩展类加载器(Extension Class Loader)
应用类加载器(Application Class Loader)
1、JVM的位置
2、JVM的体系结构
3、类加载器
类加载器分类
- 站在java虚拟机的角度看,JVM支持两种加载器,分别为引导类加载器(BootstrapClassLoader)和自定义类加载器。
- 从概念上来说自定义加载器一般是程序中由开发人员定义的一类加载器,
- 然而java虚拟机规范中并没有这样定义,而是将所有派生于抽象类ClassLoader的类加载器都划分为自定义加载器。
一般来说在java8以及以前的版本都会用到如下三种加载器:
- 启动类加载器(Bootstrap Class Loader)
- 扩展类加载器(Extension Class Loader)
- 应用类加载器(Application Class Loader)
启动类加载器(Bootstrap Class Loader)
- 该加载器使用C++实现(不会继承ClassLoader),是虚拟机自身的一部分。
- 该类加载器主要是负责加载存放在JAVA_HOME\lib目录,或者被-Xbootclasspath参数指定路径存放的,
- 并且是java虚拟机能识别的类库加载到虚拟机内存中。(eg:主要是加载java的核心类库,即加载lib目录下的所有class)
扩展类加载器(Extension Class Loader)
- 这个类加载器主要是负责加载JAVA_HOME\lib\ext目录中,或者被java.ext.dirs系统变量所指定的路径中所有类库
应用类加载器(Application Class Loader)
- 这个类的加载器是由sun.misc.Launcher$AppClassLoader来实现
- 因为该加载器是ClassLoader类中的getSystemClassLoader()方法的返回值,所以一般也称为该加载器为系统类加载器。
- 该加载器主要是加载用户类路径上所有的类库,如果应用程序中没有定义过自己的类加载器,一般情况下这个就是程序的默认加载器。
作用:
加载Class文件
比如说new Student();——就是有一个类是student,并且这个类是抽象的,当我们使用new关键字的时候,这个student就变成了一个具体的实例,这个具体的实例引用是在java栈里面,这个具体的人是放在堆里面的
(1)首先class.class先进入到class Loader中,然后class loader会去加载并初始化编程car class,然后car class就会去做实例化的操作。比如这里的car1、car2、car3(这三个实例都是来自car class同一个模板)
public class car {
public static void main(String[] args) {
// 你创建一个car会返回一个class对象
// 类是一个模板,是抽象的
// 对象是具体的
Class<car> carClass = car.class;
}
}
(2)怎么样把一个car的实例转换成car class呢,我们就需要用到getclass
public class Car {
public static void main(String[] args) {
// 你创建一个car会返回一个class对象
// 类是一个模板,是抽象的
// 对象是具体的
// 这样的话就是把一个对象类Car()实例转换成一个对象
// 它的名字实在栈里面,但是实际的对象是在堆里面
Car car1 = new Car();
Car car2 = new Car();
Car car3 = new Car();
}
}
(3)car class怎么样回到class loader呢,就需要getClassLoader
public class Car {
public static void main(String[] args) {
// 你创建一个car会返回一个class对象
// 类是一个模板,是抽象的
// 对象是具体的
// 这样的话就是把一个对象类Car()实例转换成一个对象
// 它的名字实在栈里面,但是实际的对象是在堆里面
Car car1 = new Car();
Car car2 = new Car();
Car car3 = new Car();
System.out.println(car1.hashCode());
System.out.println(car2.hashCode());
System.out.println(car3.hashCode());
Class<? extends Car> aClass1 = car1.getClass();
Class<? extends Car> aClass2 = car2.getClass();
Class<? extends Car> aClass3 = car3.getClass();
System.out.println(aClass1.hashCode());
System.out.println(aClass2.hashCode());
System.out.println(aClass3.hashCode());
}
}
输出效果:
这个结果可以看得出来同一个模板对象new出来了3个不一样的结果
包括:
- 虚拟机自带的加载器
- 启动类(根)加载器(BootstrapClassLoader)
- 扩展类加载器(ExtClassLoader)
- 应用程序(系统类)加载器(AppClassLoader)
public class Car {
public static void main(String[] args) {
// 你创建一个car会返回一个class对象
// 类是一个模板,是抽象的
// 对象是具体的
// 这样的话就是把一个对象类Car()实例转换成一个对象
// 它的名字实在栈里面,但是实际的对象是在堆里面
Car car1 = new Car();
Car car2 = new Car();
Car car3 = new Car();
System.out.println(car1.hashCode());
System.out.println(car2.hashCode());
System.out.println(car3.hashCode());
Class<? extends Car> aClass1 = car1.getClass();
// 获得类加载器
ClassLoader classLoader = aClass1.getClassLoader();// AppClassLoader用户类加载器
System.out.println(classLoader);
System.out.println(classLoader.getParent()); // ExtClassLoader 扩展类加载器
System.out.println(classLoader.getParent().getParent()); // null,1、就是不存在 2、java程序获取不到
}
}
输出效果:
(null)rt.jar的java的lang包下有个string方法
(ext)C:\Program Files\Java\jre1.8.0_171\lib\ext
appclassload(抽象类)
4、双亲委派机制
- 类加载器收到类加载的请求!
- 将这个请求向上委托给父类加载器去完成,一直向上委托,知道启动类加载器
- 启动加载器检查是否能够加载这个类,能加载就结束,使用当前的加载器,否则,抛出异常,通知子加载器加载
- 重复步骤 如果操作不正确就会出现class not found~
- null的话就是java调用不到!
过程:
- 如果一个类加载器收到了类加载请求,它首先不会自动去尝试加载这个类,而是把这个类委托给父类加载器去完成,每一层依次这样,
- 因此所有的加载请求都应该传送到顶层的启动类加载器中,
- 只有当父类加载器反馈自己无法完成该加载请求(找不到所需的类)时,这个时候子加载器才会尝试自己去加载,这个过程就是双亲委派机制!
双亲委派机制优点:
- 避免了类的重复加载
- 保护了程序的安全性,防止核心的API被修改
通过String和Student对比:
String
package java.lang;
public class String {
// 双亲委派机制:为了安全
// 1.APP--->EXC---BOOT(最终执行)
// 首先它会去BOOT找
// 然后才会去EXC
// 最后才去APP
public String toString() {
return "Hello";
}
public static void main(String[] args) {
String s = new String();
s.toString();
}
/*
1.类加载器收到类加载的请求!
2.将这个请求向上委托给父类加载器去完成,一直向上委托,知道启动类加载器
3.启动加载器检查是否能够加载这个类,能加载就结束,使用当前的加载器,否则,抛出异常,通知子加载器加载
4.重复步骤
如果操作不正确就会出现class not found~
5.null的话就是java调用不到!
*/
}
Student
public class Student {
@Override
public String toString() {
return "Hello";
}
public static void main(String[] args) {
Student student = new Student();
System.out.println(student.getClass().getClassLoader());
System.out.println(student.toString());
}
}
各个类加载器的归属关系如下:
启动类加载器负责加载的模块
平台类加载器负责加载的模块
应用程序类加载器负责加载的模块