JVM学习
第二天 类加载器与类的加载过程
类加载子系统
①类加载子系统负责从文件系统或者网络中加载class文件,class文件在文件开头有特点额文件标识
②ClassLoder只负责class文件的加载,至于是否可以运行,则由Execution Engine决定
③加载的类信息存放于一块称为方法区的内存空间,除了类的信息外,方法区中还会存放运行时常量池信息,可能还包括字符串字面量和数字常量
类加载过程
(1)加载:查找并加载类的二进制数据
1.将类的.class文件中的二进制数据读到内存中,将其放在运行时数据区的方法区内,然后再内存中创建一个java.lang.Class对像,用来封装类在方法区内的数据结构,作为方法区这个类的各种数据的访问入口。
2.类加载器分为两种:
JVM自带的加载器
①根类加载器
②扩展类加载器
③系统类加载器
用户自定义类加载器:java.lang.ClassLoader的子类
3.加载的方式
①从本地系统直接加载
②网络下载class文件
③从zip.jar等归档文件中加载的class文件
④从专有数据库提取的class文件
⑤Java源文件动态编译class文件(jsp编译为servlet)
(2)链接:链接又有三个步骤
①验证:确保class文件的字节流中包含信息符合当前虚拟机要求,保证被加载了的正确性。
类文件的结构检查
语义检查
字节码验证
二进制兼容性的验证
②准备:为类的静态变量分配内存,并将其初始化为默认值,这里不包含final修饰的static。不会为实例变量分配初始值
③解析:把类中的符号引用转换为直接引用过程。事实上,解析操作往往会伴随着JVM在执行完初始化之后再执行。符号引用就是一组符号来描述所引用的目标
(3)初始化:为类的静态变量赋值
类的初始化过程就是执行类的构造器方法的过程,此方法不需要定义,时javac编译器自动收集类说有类变量的赋值动作和静态代码块中的语句合并来的
(4)使用
类的实例化
①为新的对象分配内存
②为实例变量赋值默认组
③为实例变量赋正确的初始值
④Java编译器为它编译的每一个类都至少生成一个实例化初始化方法,再java的class文件中,这个实例初始化方法称为“”.针对源代码中每一个类的构造方法,java编译器都产生一个方法
java程序对类的使用分为两种:
主动使用
1.创建类的实例
2.访问某个类和接口的静态变量(getstatic),或者对该静态变量赋值(putstatic)
3.调用类的静态方法(invokestatic)
4.反射(Class.forName(“Tste”))
5.初始化子类
6.Java虚拟机启动时被标明为启动类的类
7.JDK1.7开始提供的动态语言的支持java.lang.invoke.MethodHandle实例的解析结果REF_getStatic,REF_petStatic,REF_invokestatic对应的类没有初始化,则初始化
被动使用
(5)卸载
类加载器
(1)ClassLoader类,是一个抽象类,所有的的类加载器都继承于此类(不包含根类加载器)
(2)双亲委派机制
Java虚拟机对class文件采用按需加载的方式,也就是当许需要使用该类才会将他的class对象加载到内存中生成class对象,而且加载某个类的class文件时,Java虚拟机采用的时双亲委派模式。及把请求交给父类出来,他是一种委派模型
(3)工作原理
①如果一个类加载器收到类类加载请求,它并不会自己先去加载,而是将这个委托给父类加载器去执行。
②如果父类加载器还存在其父类加载器,着进一步向上委托,依次递归请求最终将到达顶层的启动类加载器
③如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成,则子加载器尝试自己加载。这就是双亲委派机制。
自定义类加载器
package com.jvm.course;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
/**
* 〈自定义类加载器 --虽然加载了,但是不是次自定义类加载器加载的,是由系统类加载器加载。双亲委派的原因〉
*
* @author PitterWang
* @create 2020/5/20
* @since 1.0.0
*/
public class CustomClassLoader extends ClassLoader{
private String classLoaderName;
private final String fineExtiosion = ".class";
public CustomClassLoader(String classLoaderName){
super(); //使用默认父类加载器
this.classLoaderName = classLoaderName;
}
public CustomClassLoader(ClassLoader parent,String classLoaderName){
super(parent); //显式使用父类加载器
this.classLoaderName = classLoaderName;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] data = this.loadClassData(name);
return this.defineClass(name,data,0,data.length);
}
private byte[] loadClassData(String name) {
InputStream is = null;
byte[] data = null;
ByteArrayOutputStream baos = null;
try {
this.classLoaderName = this.classLoaderName.replace(".","/");
is = new FileInputStream(new File(name + this.fineExtiosion));
baos = new ByteArrayOutputStream();
int ch;
while (-1 != (ch = is.read())){
baos.write(ch);
}
data = baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
is.close();
baos.close();
}catch (Exception e){
e.printStackTrace();
}
}
return data;
}
@Override
public String toString() {
return "CustomClassLoader{" +
"classLoaderName='" + classLoaderName + '\'' +
'}';
}
public static void test(ClassLoader classLoader) throws Exception{
Class<?> clazz = classLoader.loadClass("com.jvm.course.Test");
Object object = clazz.newInstance();
System.out.println(object);
}
public static void main(String[] args) {
CustomClassLoader customClassLoader = new CustomClassLoader("load");
try {
test(customClassLoader);
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.jvm.course;
/**
* 〈类加载器使用测试〉
*
* @author PitterWang
* @create 2020/5/20
* @since 1.0.0
*/
public class ClassLoaderTest {
public static void main(String[] args) {
/**
* 获取系统类加载器:sun.misc.Launcher$AppClassLoader@18b4aac2
*/
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
/***
* 获取扩展类加载器:sun.misc.Launcher$ExtClassLoader@2a3046da
*/
ClassLoader extClassLoader = systemClassLoader.getParent();
System.out.println(extClassLoader);
/**
* 获取引导类/根类加载器 :null
*
*/
ClassLoader rootClassLoader = extClassLoader.getParent();
System.out.println(rootClassLoader);
/**
* 系统自定义的类用系统类加载器加载:sun.misc.Launcher$AppClassLoader@18b4aac2
*/
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
System.out.println(classLoader);
/**
* String是由引导类加载器加载的:null
*/
ClassLoader classLoader1 = String.class.getClassLoader();
System.out.println(classLoader1);
}
}