作用:当程序用到某个类中,由类加载器将类的字节码加载进内存。
JAVA虚拟机中可以安装多个加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader, AppClassLoader
xxx.class.getClassLoader.getClass( ).getName( );//获取某个类的类加载器的名称。
但是调用JAVA提供的类是由BootStrap加载器加载,底层加载器。用get.ClassLoader返回的是空。
类加载也是一个java类,因为其它是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是JAVA类的,这正是BootStrap,由C++编写的。
类加载器之间的父子关系和管辖范围
BootStap JRE/lib/rt.jar(JAVA提供的类都在rt.jar包里)
ExtClassLoader JRE/lib/ext/*.jar(ext扩展jar包存放目录,如果把自己写的类导成jar包放到此目录下。会被ExtClassLoader加载器加载)
AppClassLoader ClassPath指定的所有jar或目录
(优先级问题:先父后子)
自定义类加载器,需要继承ClassLoader类,构造方法中需指定加载类的父类。默认有。
类加载器的委托机制
当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?
1. 首先当前线程的类加载器去加载线程中的第一个类。
Thread类中有一个方法:setContextClassLoader(ClassLoader cl)。
2. 如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。
3. 还可以直接调用ClassLoader.loadClass( )方法来指定某个类加载器去加载某个类。
每个类加载器加载类时,又先委托给其上级类加载器。
1. 当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFooundException,不是再去找发起者类加载器的子类了,因为没有getChild方法,即使有,那有多个子类,找哪一个呢?
2. 对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的itcast.jar包中后,运行结果为ExtClassLoader的原因。
面试题:我们可以写一个java.lang.System包
答:通常是不可以的,因为如果我写一个System类放到ClassPath目录下,ClassPath目录下的类都是由AppClassLoader加载的,AppClassLoader会委托祖宗类,System在祖宗类中存在,会加载。所以根本不可能加载我的这个System类。不过有一种办法,就是我自己写一个类加载器,而这个类加载器不用委托祖宗类。
1.知识讲解:
自定义的类加载器的必须继承ClassLoader抽象类
loadClass()方法与findClass()方法,loadClass() 方法是去委托父类,我们自己写加载类只要覆盖findClass方法。
defineClass(String name)方法:将得到的class文件转换成字节码
2.编程步骤:
编写一个对文件内容进行简单加密的程序。
编写了一个自己的类装载器,可实现对加密过的类进行装载和解密。
编写一个程序调用类加载器加载类,在源程序中不能用该类名定义引用变量,因为编译器无法识别这个类。程序中可以除了使用ClassLoader.load方法之外,还可以使用设置线程的上下文类加载器或者系统类加载器,然后再使用Class.forName。
3.实验步骤:
对不带包名的class文件进行加密,加密结果存放到另外一个目录,例如: java MyClassLoader MyTest.class F:\itcast
运行加载类的程序,结果能够被正常加载,但打印出来的类装载器名称为AppClassLoader:java MyClassLoader MyTest F:\itcast
用加密后的类文件替换CLASSPATH环境下的类文件,再执行上一步操作就出问题了,错误说明是AppClassLoader类装载器装载失败。
删除CLASSPATH环境下的类文件,再执行上一步操作就没问题了。
MyClassLoader.java
package cn.test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class MyClassLoader extends ClassLoader {
/**
* @param args
*/
// public static void main(String[] args) throws Exception {
// // TODO Auto-generated method stub
// String sourceFilePath = args[0];
// String targetDir = args[1];
// String myPath = MyClassLoader.class.getResource("").getPath();
// String[] path = myPath.split("bin");
// String targetFilePath =
// path[0]+targetDir+"\\"+sourceFilePath.substring(sourceFilePath.lastIndexOf('\\')+1);
//
// InputStream is = new FileInputStream(sourceFilePath);
// OutputStream os = new FileOutputStream(targetFilePath);
//
// encrypt(is,os);
// }
public static void encrypt(InputStream is, OutputStream os) {
int by = -1;
try {
while ((by = is.read()) != -1) {
os.write((byte) by * 0xff);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private String classPath;
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// TODO Auto-generated method stub
try {
InputStream is = new FileInputStream(classPath + File.separator
+ name + ".class");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
encrypt(is, baos);
byte[] bytes = baos.toByteArray();
return defineClass(bytes, 0, bytes.length);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return super.findClass(name);
}
public MyClassLoader() {
// TODO Auto-generated constructor stub
}
public MyClassLoader(String classPath) {
this.classPath = classPath;
}
}
MyClassTest.java 测试类
package cn.test;
public class MyClassTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
Class clazz = new MyClassLoader("myclasslib").loadClass("MyClass");
Object obj = clazz.newInstance();
System.out.println(obj.toString());
System.out.println("====================================");
ClassLoader clazzLoader = obj.getClass().getClassLoader();
while (clazzLoader != null) {
System.out.println(clazzLoader.getClass().getName());
clazzLoader = clazzLoader.getParent();
}
if (clazzLoader == null)
System.out.println("BootStrap");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}