bilibili-深入理解JVM 虚拟机 学习笔记
JVM学习笔记 1
JVM学习笔记 2
JVM学习笔记 3
JVM学习笔记 4
P14_ClassLoader源码分析与实例剖析(14)
类加载器是负责加载类的对象。ClassLoader 类是一个抽象类。如果给定类的二进制名称,那么类加载器会试图查找
或生成
构成类定义的数据。一般策略是将名称转换为某个文件名,然后从文件系统读取该名称的“类文件”。
每个 Class 对象
都包含一个对定义它的 ClassLoader 的引用
。
数组类的 Class 对象不是由类加载器创建的
,而是由 Java 运行时根据需要自动创建。数组类的类加载器由 Class.getClassLoader() 返回,该加载器与其元素类型的类加载器是相同的
;如果该元素类型是基本类型,则该数组类没有类加载器
。
应用程序需要实现 ClassLoader 的子类,以扩展 Java 虚拟机动态加载类的方式。
类加载器通常由安全管理器使用,用于指示安全域。
ClassLoader 类使用委托模型
来搜索类和资源
。每个 ClassLoader 实例都有一个相关的父类加载器。需要查找类或资源时,ClassLoader 实例会在试图亲自查找类或资源之前,将搜索类或资源的任务委托给其父类加载器。虚拟机的内置类加载器(称为 “bootstrap class loader”)本身没有父类加载器,但是可以将它用作 ClassLoader 实例的父类加载器。
通常情况下,Java 虚拟机以与平台有关的方式,从本地文件系统中加载类。例如,在 UNIX 系统中,虚拟机从 CLASSPATH 环境变量定义的目录中加载类。
然而,有些类可能并非源自一个文件;它们可能源自其他来源(如网络),也可能是由应用程序构造的。defineClass 方法
将一个 byte 数组转换为 Class 类的实例。这种新定义的类的实例可以使用 Class.newInstance 来创建。
类加载器所创建对象的方法和构造方法可以引用其他类。为了确定引用的类,Java 虚拟机将调用最初创建该类的类加载器的 loadClass 方法。
– ClassLoader JavaDoc
package new_package.jvm.p14;
public class MyTest15 {
public static void main(String[] args) {
String[] strings = new String[2];
System.out.println(strings.getClass().getClassLoader());
MyTest15[] myTest15s = new MyTest15[2];
System.out.println(myTest15s.getClass().getClassLoader());
int[] ints = new int[2];
System.out.println(ints.getClass().getClassLoader());
}
}
// null
// sun.misc.Launcher$AppClassLoader@18b4aac2
// null
P15_自定义类加载器深入详解(15)
网络类加载器子类必须定义方法 findClass
和 loadClassData,以实现从网络加载类。下载组成该类的字节后,它应该使用方法 defineClass 来创建类实例。示例实现如下:
class NetworkClassLoader extends ClassLoader {
String host;
int port;
public Class findClass(String name) {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassData(String name) {
// load the class data from the connection
. . .
}
}
package new_package.jvm.p15;
import java.io.*;
public class MyClassLoader extends ClassLoader {
public static final String fileExtension = ".class";
public MyClassLoader() {
super();
}
private byte[] loadClassData(String name) {
byte[] data = null;
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = new FileInputStream(new File(name));
outputStream = new ByteArrayOutputStream();
int ch;
while (-1 != (ch = inputStream.read())) {
outputStream.write(ch);
}
data = ((ByteArrayOutputStream) outputStream).toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
inputStream.close();
outputStream.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return data;
}
@Override
protected Class<?> findClass(String name) {
String fileName = name + fileExtension;
byte[] bytes = loadClassData(fileName);
return defineClass(fileName, bytes, 0, bytes.length);
}
}
---
package new_package.jvm.p15;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MyClassLoaderTest {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
ClassLoader classLoader = new MyClassLoader();
Class clazz = classLoader.loadClass("MD5Util");
String str = "Hello World";
System.out.println(MD5UtilCopy.MD5Encode(str));
Object obj = clazz.newInstance();
Method method = clazz.getMethod("MD5Encode", new Class[]{String.class});
Object result = method.invoke(obj, new Object[]{str});
System.out.println(result);
}
}