类加载器
类加载器负责加载类的对象,它可以在将类加载到虚拟机中的时候坚持类的完整性。
每个程序至少拥有三个类加载器:
1.引导类加载器
2.扩展类加载器
3.系统类加载器(也称应用类加载器)
引导类加载器负责加载系统类(通常从JAR文件rt.jar中进行加载)。它是虚拟机整体中的一部分,通常用C语言来实现。引导类加载器没有对应的ClassLoader对象,如,String.class.getClassLoader()将返回null。
扩展类加载器用于从jre/lib/ext目录加载“标准的扩展”。可以将JAR文件放入目录,这样即使没有任何类路径,扩展类加载器也可以找到其中的各个类。
系统类加载器用加载应用类。它由CLASSPATH环境变量或者-classpath命令行选项设置的类路径中的目录里或者JAR/ZIP文件里查找这些类
在Sun公司的Java语言实现中,扩展类加载器和系统类加载器都是Java来实现的。它们都是URLClassLoader类的实例
警告:如果JAR文件放入jre/lib/ext目录中,并且在它的类中有一个类需要调用系统类或者扩展类,那么就会遇到麻烦。扩展类加载器并不使用类路径。在使用扩展目录来解决类文件的冲突之前,要牢记这种情况
注意:除了所有已经提到的位置,还可以从jre/lib/endorsed目录中加载。这种机制只能用于将某个标准的Java类库替换为更新的版本(例如那些支持XML和CORBA的类)
类加载器的层次结构
类加载器有一种父/子关系。除了引导类加载器外,每个类加载器都有一个父类加载器。根据规定,类加载器会为它的父类加载器提供一个机会,以便加载任何给定的类,并且只有在其父类加载器加载失败时,它才会加载该给定类。例如,当要求系统类加载器加载一个系统类(比如,java.util.ArrayList)时,它首先要求扩展类加载器进行加载,扩展类加载器则首先要求引导类加载器进行加载。引导类加载器查找并加载rt.jar中的这个类,而无须其他类加载器做更多的搜索
自定义类加载器
需要继承ClassLoader类并重写父类findClass(String className)方法。
ClassLoader超类的loadClass方法用于将该类的加载操作委托给其父类加载器去进行,只有当该类尚未加载并且父类加载器也无法加载该类时,才调用findClass方法
如果要实现该方法,要做到以下几点:
1.为来自本地文件系统或者其它来源的类加载其字节码
2.调用ClassLoader超类的defineClass方法,向虚拟机提供字节码
常用方法:
java.lang.Class
ClassLoader getClassLoader():返回该类的类加载器,如果父类是引导类加载器则返回null
java.lang.ClassLoader
protected Class defineClass(String name,byte[] b,int off,int len):将一个 byte 数组转换为 Class 类的实例。
protected Class findClass(String name):使用指定的二进制名称查找类
InputStream getResourceAsStream(String filePath):返回读取指定资源的输入流。
static ClassLoader getSystemClassLoader():返回委托的系统类加载器。
import java.util.Date;
public class ClassLoaderAttachment extends Date {
private static final long serialVersionUID = 1L;
public String toString() {
return "hello itcast!";
}
}
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 自定义类加载器类
* @author wxd
*
*/
public class MyClassLoader extends ClassLoader {
private String classDir;
public MyClassLoader() {
}
public MyClassLoader(String classDir) {
this.classDir = classDir;
}
public static void cypher(InputStream ips, OutputStream ops)
throws IOException {
int b = -1;
while ((b = ips.read()) != -1) {
ops.write(b);
}
ips.close();
ops.close();
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String classFileName = classDir + "\\" + name+".class";
try {
FileInputStream fis = new FileInputStream(classFileName);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cypher(fis, bos);
fis.close();
byte[] bytes = bos.toByteArray();
return defineClass(bytes, 0, bytes.length);
} catch (Exception e) {
}
System.out.println("classFileName:" + classFileName);
return super.findClass(classFileName);
}
}
import java.util.Date;
public class ClassLoaderTest {
@SuppressWarnings("rawtypes")
public static void main(String[] args) throws Exception {
System.out.println(ClassLoaderTest.class.getClassLoader().getClass()
.getName());
System.out.println(System.class.getClassLoader());
ClassLoader loader = ClassLoaderTest.class.getClassLoader();
while (loader != null) {
System.out.println(loader.getClass().getName());
loader = loader.getParent();
}
System.out.println("loader:" + loader);
Class clazz =new MyClassLoader("itcastlib").loadClass("ClassLoaderAttachment");
Date date = (Date) clazz.newInstance();
System.out.println("date:"+date);
}
}