绪论
谈谈类从编译到执行的过程
- 编译器将Robot.java源文件编译为Robot.class字节码文件
- ClassLoader将字节码转换为JVM中的Class对象
- JVM利用Class对象实例化Robot对象
谈谈CLassLoader:
- ClassLoader再java中有着非常重要的作用,它主要工作在Class的装载阶段,其主要作用是从系统外部获得Class二进制数据流。他是java的核心组件,所有的Class都是由ClassLoader进行记载的,ClassLoader负责通过将Class文件里的二进制数据流装进系统,然后交给java虚拟机进行链接、初始化等操作。
Classloader的种类有哪些
- BootStrapClassLoader:C++编写,加载核心库java.*
- ExtClassLoader:java编写,加载扩展库javax.*
- AppClassLoader:java编写,加载程序所在目录中的类
- 自定义ClassLoader:Java编写,定制化加载
类的装载过程
- 加载 -> 通过ClassLoader加载class文件字节码,生成class对象
- 链接 ->
1、校验:检查加载的class的正确性和安全性
2、准备:为类变量分配存储空间并设置类变量初始值
3、解析:JVM将常量池内的符号引用转换为直接引用(可选) - 初始化 -> 执行类变量赋值和静态代码块
1、使用new字节码指令创建类的实例,或者使用getstatic、putstatic读取或者设置一个静态字段的值(放入常量池中的常量除外),或者调用一个静态方法的时候,对应类必须进行过初始化。
2、通过反射进行调用的时候,如果类没有进行过初始化,则要首先进行初始化。
3、当初始化一个类的时候,如果发现父类没有进行过初始化,则首先触发父类初始化。对于静态字段,自由直接定义这个字段的类才会被初始化,因此,通过其子类引用父类中定义的静态字段,只会触发父类的初始化而不会触发子类的初始化。
4、当虚拟机启动时,用户需要指定一个主类,(包含main方法的类)虚拟机会首先初始化这个类。
loadClass 和 forName的区别
- Class.forName得到的class是已经初始化完成的
- Classloader.loadClass得到的class是还没有链接的
双亲委派机制图示
自定义类加载器
新建需要被加载的类ByteCodeSimple.java,放在桌面并通过javac编译为.class文件
public class ByteCodeSimple {
static {
System.out.println("new instance start");
}
public static int add(int a, int b) {
int c = 0;
c = a + b;
return c;
}
}
自定义类加载器实现 CustomClassLoader.java
package com.***.demo.test;
import java.io.*;
public class CustomClassLoader extends ClassLoader {
private String path;
private String classLoaderName;
public CustomClassLoader(String path, String classLoaderName) {
this.path = path;
this.classLoaderName = classLoaderName;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] b = loadClassData(path + name + ".class");
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassData(String name) {
InputStream in = null;
ByteArrayOutputStream out = null;
try {
in = new FileInputStream(new File(name));
out = new ByteArrayOutputStream();
int i = 0;
while ((i = in.read()) != -1) {
out.write(i);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
in.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return out.toByteArray();
}
}
测试类
package com.***.demo.test;
public class CustomClassLoaderTest {
public static void main(String[] args) throws Exception {
String path = "C:\\Users\\Desktop\\";
String className = "ByteCodeSimple";
CustomClassLoader myClassLoad = new CustomClassLoader(path, "自定义类加载器");
Class<?> c = myClassLoad.loadClass(className);
c.newInstance();
}
}
测试结果
new instance start
Process finished with exit code 0