小知识
BootStarap 是一个JAVA虚拟机器 是存在于JAVA内核中的(也是最高级别的类加载器)
System类是由BootStarap类加载器加载的,如果类加载器类为null,则这个类加载器为BootStarap
几个类加载器的职责
BootStarap
加载jre/lib/*.jar 例如rt.jar System
ExClassLoader
加载jre/lib/ext/*.jar
AppClassLoader
自定义类一般默认都使用该类加载器加载 此类加载器加载classpath指定的所有jar或目录
系统的类加载执行顺序
首先会在BootStarap里面查找有没有这个jar包,
如果没有的话会到ExClassLoader 里面查找,
如果还未找到的话才会在APPClassLoader里面查找,找到的话就进行加载 找不到的话就报类无法找到的异常
自定义类加载器的执行顺序
首先如果子类覆盖loadclass方法,则不会找找父加载器,如果不覆盖loadclass方法则执行的时候会自动的父类去查找,
如果找不到的话,才回到本类加载器来查找 执行自定义类中重写的方法findClass(String name)在本加载器中查找是否有此类
如果加载的类中又调用另外一个那。那么由当前类加载器来加载那个被调用的类
源代码:
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
自定义类加载器
1、自己自定义一个类加载器的时候必须继承自类ClassLoader,并且指定一个父加载器
2、重写findClass(String name)方法
指定自义类的类加载器方法
1、自定义类加载器Name.LoadClass();
2、Thread.setContextClassLoader(ClassLoader cl);
自定义类加载器的使用示例:
首先自定义一个要被加载的类:继承自Date并实现toString()方法
public class Demo37_exDate extends Date {
@Override
public String toString() {
System.out.println("Hello,Word");
return null;
}
}
然后自定义一个公共方法:用于对类进行加密
public static void coyher(InputStream is, OutputStream os)
throws Exception {
int b = 0;
while ((b = is.read()) != -1) {
os.write(b ^ 0xff);
}
is.close();
os.close();
}
对要被使用的类进行加密处理后,保存到ItcastLib目录下
传入值为 D:\Workspaces\MyEclipse8.5\Test\WebRoot\WEB-INF\classes\Demo37_exDate.class D:\Workspaces\MyEclipse8.5\Test\ItcastLib\newClass.class
FileInputStream fis = new FileInputStream(args[0]);
FileOutputStream fos = new FileOutputStream(args[1]);
copyher(fis, fos);
自定义一个类加载器,需要覆盖findClass(String name)方法
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
name = fileDir +File.separator+ name+".class";
FileInputStream fis = new FileInputStream(name);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
coyher(fis, baos);
byte[] b = baos.toByteArray();
Class c = defineClass(b, 0, b.length);
return c;
} catch (Exception e) {
}
return null;
}
使用自定义类加载器加载要已定义的被加载的类:
Demo37 d = new Demo37("ItcastLib");
Class c = d.loadClass("newClass"); //如果在包下面的话,必须要加上包名 不使用自定义类加载器还是系统的类加载器,默认根目录为系统目录
Date date = (Date)c.newInstance(); //被接收方之所以是父类,如果是子类的话,编译器会编译并加载我们加密过的类,会报错
date.toString();
-