上图所示的是类加载的顺序,按照大的顺序可以分为加载、链接、初始化
其中链接又可以分成验证、准备、解析三个步骤
加载
1.将类的class文件读入到内存中
加载类文件的方式有: 1. 本机文件加载 2.jar包加载 3.网络加载 4.源文件动态编译加载
2.创建一个java.lang.class文件
连接
1.验证:类结构是否正确,是否与其他类协调一致
2.准备:为类分配内存,并设置默认初始值
3.解析:将二进制文件的符号引用替换成直接引用
初始化
对类的变量进行初始化
使用静态代码块初始化、申明类变量初始值
java 里有3中默认的类加载器
加载器种类
解释
启动类加载器
从JAVA_HOME/lib 路径下找
扩展类架子器
从JAVA_HOME/lib/ext 路径下找
应用程序类加载器
从classpath 路径下找
自定义加载器
我们程序员自己定义的加载器
new 一个类的时候 ,首先jvm会去看下当前类加载器有没有父类的加载器,有就把这个加载请求交给父类,一直如此,直到到达最顶层的启动类加载器,然后,在一级一级的往下看能不能加载,能加载就加载,不能就把这个加载任务交给子类
举一个例子,当我new Dog() 的时候
JAVA_HOME/lib
里找,没有,交还给扩展类加载器JAVA_HOME/lib/ext
里找,没有交还给应用程序类加载器接下去我们实现一个自定义的类加载器,利用这个加载器来加载一个类
首先简单的构建一个类
package com.example.demo;
public class Dog {
public String name;
}
这是一个很简单的类,我们把它编译成class 文件放在d:
盘的根目录下
构建我们自己的类加载器
public class MyLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
File file = new File("D:/Dog.class");
try {
FileInputStream fileInputStream = new FileInputStream(file);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
//每次读取的大小是4kb
byte[] b = new byte[4 * 1024];
int n = 0;
while ((n = fileInputStream.read(b)) != -1) {
outputStream.write(b, 0, n);
}
//将Dog.class类读取到byte数组里
byte[] classByteArray = outputStream.toByteArray();
//调用defineClass 将byte 加载成class
Class<?> aClass = this.defineClass(name, classByteArray, 0, classByteArray.length);
return aClass;
} catch (Exception e) {
e.printStackTrace();
}
return super.findClass(name);
}
}
上面的代码中,我们自定义了一个类让他去继承ClassLoader
,然后重写其中的findClass
方法,我们重写后的逻辑就是自己的指定的目录,也就是d盘
下找到Dog.class
文件 然后读取到一个byte数组中,然后调用defineClass
加载这个类。
下面用一个简单的程序测试下
public class UserDemo {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
MyLoader myLoader = new MyLoader();
Class<?> aClass = Class.forName("com.example.demo.Dog", true, myLoader);
Object o = aClass.newInstance();
System.out.println(o);
System.out.println(o.getClass().getClassLoader());
}
}
这里的Class.forname 和以前不一样,我们后面对了两个参数,true代表类重新加载,myLoader就是我们自定义的类加载器
运行后显示:
com.example.demo.Dog@2e817b38
com.example.demo.MyLoader@4d405ef7
可以看到已经使用了我们自定义的类加载器。
这里有一点要注意,就是个别编译器比较智能,如我使用的idea,他们会自定编译,直接把你的java文件编译成class 放入classpath下去了,所以在运行请务必吧这个文件删除,如果你用的是idea 把整个target删除就行
手机扫一扫
移动阅读更方便
你可能感兴趣的文章