---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
类加载器:
类加载器:就是把.class文件从硬盘中读出来变成字节码并加载进内存中的一个工具
(1) Java虚拟机中可以安装多个类加载器,系统默认三个主要的类加载器,每个类负责加载特定位置的类
(2)类加载器也是java类,以为其他是java类的类加载器本身也要被类加载器加载,所以必须有第一个类加载器不属于java类,这个类加载器是:BootStrap,其嵌进了java虚拟机内核里,java虚拟机一启动就已经存在里面了
(3)java虚拟机中的所有类加载器采用具有父子关系的树形结构进行组织,在实例化每个类加载器对象时,需要为其制定一个父级类加载器对象或者采用系统类加载器为其父级类加载
类加载委托机制
(1)当类java虚拟机要加载一个类的时候
会派当前线程的类加载器去加载线程中的第一个类
如果A类中引用了B类,java虚拟机将使用加载类A的类加载器去记载某个类
还可以直接调用Classloader.loadClass()方法来指定某个类加载器去加载某个类
(2)每个类加载器加载类时,又先委托给其上级类加载器
当所有祖宗类加载器没有加载到类,回到发起类加载器,还加载不了,则抛异常
我的理解:每个类加载器本身只能加载特定位置的类,但是,可以委托其他类加载器去加载某个类。当某一个类加载器需要加载某个类时,会优先委托给其上级类加载器去加载,如果所有上级所负责的位置不存在想要加载的类时,就一级一级类似递归一样,返回到给委托发起的类加载器,再由发起的类加载器自行加载
委托机制解决了什么问题?
java提供了很多系统级别的类,如:java.lang.System
如果用户自定义了一个类,与系统的类一直,也叫System,那么在使用的时候,真正加载进内存的必定是java系统提供的System,因为委托机制确保了上层的类加载优先加载,而上层的类加载器就会把java系统的System给加载了
编写自定义类加载器
自定义类加载器必须继承ClassLoader,并且覆盖父类的findClass(),而不用覆写loadClass()方法
为什么要覆写findClass(Stringname):因为存在类加载器的委托机制,在loadClass()内部是会先委托给父加载器,当父加载器找不到后返回,再调用findClass(String name)方法,也就是你自定义的类加载器去找。所以只需要覆写findClass方法,就能实现用自定义的类加载器加载类的目的
这是因为,自定义类加载器,会把需要加载的类放在自定义的目录中,而java中已有的类加载器默认指定的目录而不是自定义的目录,所以会找不到。此时会调用你复写的findClass()方法,调用自定义的类加载器去指定的目录加载类
需求:
编写一个对文件内容进行简单加密的程序
编写好了一个自己的类加载器,可实现对加密过来的类进行加载和解密。
编写一个程序,调用类加载器加载类,在源程序中不能用该类名定义引用变量,因为编译器无法识别这个类,程序中除了可使用ClassLoader的loadClass方法外,还可以使用设置线程的上下文类加载器或系统类加载器,然后再使用Class.forName。
代码:
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class MyClassLoader extends ClassLoader{
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
String srcPath = args[0];
String destDir = args[1];
FileInputStream fis = new FileInputStream(srcPath);
String destFileName = srcPath.substring(srcPath.lastIndexOf('\\')+1);
String destPath = destDir + "\\" + destFileName;
FileOutputStream fos = new FileOutputStream(destPath);
cypher(fis,fos);
fis.close();
fos.close();
}
private static void cypher(InputStream ips ,OutputStream ops) throws Exception{
int b = -1;
while((b=ips.read())!=-1){
ops.write(b ^ 0xff);
}
}
private String classDir;
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// TODO Auto-generated method stub
String classFileName = classDir + "\\" + name.substring(name.lastIndexOf('.')+1) + ".class";
try {
FileInputStream fis = new FileInputStream(classFileName);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cypher(fis,bos);
fis.close();
System.out.println("aaa");
byte[] bytes = bos.toByteArray();
return defineClass(bytes, 0, bytes.length);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public MyClassLoader(){
}
public MyClassLoader(String classDir){
this.classDir = classDir;
}
}
---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
详细请查看:http://edu.csdn.net