类加载器加载.class具体还要成三步:
一、加载
生成代表该类的Class实例
二、链接
1、验证:主要是验证字节码文件无误,因为字节码文件是可以被认为修改的。
2、准备:准备阶段会进行默认初始化,如下代码:
public class Test01 {
private int i=88;
public static void main(String[] args) {
}
}
默认初始化就是在准备阶段先把 i 赋值为0,当然如果是String类型就是null;
3、解析
三、初始化
这里解释一下初始化的最后一点:需要new 一个类时,这个类就会被加载,在类加载的初始化阶段就会调用类构造器的方法,如果两个线程同时new,那么就需要排队访问方法。
public class DeadThreadTest {
public static void main(String[] args) {
Runnable runnable=()->{
System.out.println(Thread.currentThread().getName()+"开始");
DeadThread deadThread = new DeadThread();
System.out.println(Thread.currentThread().getName()+"结束");
};
new Thread(runnable,"线程1").start();
new Thread(runnable,"线程2").start();
}
}
class DeadThread{
static {
if(true){
System.out.println(Thread.currentThread().getName()+"正在加载DeadThread");
while (true){
}
}
}
}
因为方法是收集类变量和合并static代码块,所以当static代码块发生死循环时,一个线程就一直占着锁,另一个线程访问不了方法。
类加载器分类
扩展类加载器和系统类加载器都间接继承了ClassLoder这个类,所以他们两个都为自定义类加载器,如果我们写个类继承ClassLoder类,那么也为自定义类加载器。引导类加载器是由C++写的,自定义类加载器都是用java写的,所以可以从代码层面看到自定义类加载器,而引导类加载器看不到。
//1、获取类的类加载器
public class Test03 {
public static void main(String[] args) throws ClassNotFoundException {
//1、获取系统类的类加载器,负责我们写的一些类-----如负责Java-classpath或java.class.path目录下的类或jar包的装入工作
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
//2、获取扩展类的类加载器<——系统类的类加载器的父类加载器----负责jre/lib/ext目录下的jar包等
ClassLoader ext = systemClassLoader.getParent();
System.out.println(ext);
//3、获取根加载器<——扩展类的类加载器的父类加载器
//由于根加载器是由C++编写的,负责Java的核心库的。
ClassLoader parent = ext.getParent();
System.out.println(parent);
//测试用户自定义类是哪个类加载器加载的
ClassLoader classLoader = Class.forName("com.yiheng.yiheng_03_classLoder.Test03").getClassLoader();
System.out.println(classLoader);
//测试JDk内置类-Java核心类是哪个加载器加载的
ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classLoader1);
//测试系统类的jar包会从些目录加载
System.out.println(System.getProperty("java.class.path"));
/*
E:\JAVA\Java\jdk-1.8\jre\lib\charsets.jar;
。。。
。。。
E:\JAVA\Java\jdk-1.8\jre\lib\rt.jar;
E:\JavaSE\Base\javaBase-02-AnnotationAndreflection\target\classes;
E:\JAVA缓存文件\IntelliJ IDEA 2021.1.3\lib\idea_rt.jar
*/
}
}
结果:
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@1b6d3586
null
sun.misc.Launcher$AppClassLoader@18b4aac2
null
可以看出Java核心类是由引导类加载器加载的,而且扩展类加载器和系统类加载器也是一个类,它们两个加载器都是由引导类加载器加载的。
用户自定义类加载器
目的:
隔离加载类
修改类的加载方式
扩展加载源
防止源码泄露(加密解密)
关于ClassLoder类
1、它是一个抽象类,所有类加载器(不包括引导类加载器)都继承字它