------- android培训、java培训、期待与您交流! ----------
类加载器:
系统默认有3个类加载器 AppClassLoader >> ExtClassLoader >> BootStrap
AppClassLoader:加载CLASSPATH指定的所有jar或目录
ExtClassLoader:加载jre/lib/ext/*.jar,加载ext下所有的jar包
BootStrap:加载jre/lib/rt.jar ,加载lib下的rt.jar。BootStrap不是java类,所以BootStrap的字节码为null,他是用C++写的一段二进制代码
Java虚拟机要加载一个类时:
首先用当前线程的类加载器去加载线程中的第一个类。
如果说这个类中还引用了其他类,那也是用加载这个类的加载器去加载。
也可以用ClassLoader.loadClass();方法来指定一个类加载器去加载。
委托机制:
类加载器在加载的时候有一个委托机制,也就是说当前加载器不会马上在自己的范围内找类加载,而是委托上级进行加载,一直委托到BootStrap,如果BootStrap在rt.jar中没找到就又一级一级的返回在其他加载器查找加载,如果返回到当前加载器也没有找到该类的话就抛出异常: ClassNotFoundException,即使当前加载器下还有加载器也不会向下查找了。
委托机制还有个一个好处就是可以保证一个类只被加载一次,如果还要去加 载的话会先根据这个委托机制上下看一看这个类被加载过没有,如果加载过 了直接返回一份字节码就是了。
自定义类加载器加密class文件:
创建一个类继承ClassLoader,创建一个加密的class文件的方法,重写finadClass方法(类加载器内部在加载类的时候是自动调用loadClass方法,而loadClass方法内部会自动的调用上级类加载器加载,以此类推,如果最后返回回来上级类加载器都没找到,则又loadClass()又调用本类的fiandClass方法,所有只重写fiandClass就行了),
public class ClassLoaderAttachment extends Date {
public String toString(){
return "hello,itcast heima";
}
}
public class MyClassLoader extends ClassLoader {
public static void main(String[] args) throws Exception {
//接收传入的参数 ,一个为原class文件的地址,另一个为加密后文件的地址
String srcPath = args[0];
String destPath = args[1] + "\\" + srcPath.substring(srcPath.lastIndexOf("\\"));
//读取文件
FileInputStream fis = new FileInputStream(srcPath);
//写入
FileOutputStream fos = new FileOutputStream(destPath);
//调用加密方法,对class文件进行加密
cypher(fis,fos);
fis.close();
fos.close();
}
//加密
public static void cypher(InputStream is, OutputStream os) throws Exception{
// System.out.println("jiami");
int b = -1;
while((b = is.read()) != -1){
os.write(b ^ 0xff);
}
}
private String classDir;
MyClassLoader(){}
MyClassLoader(String classDir){
//接收地址
this.classDir = classDir;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
//拼接class文件地址
name = classDir + "\\" + name + ".class";
try {
FileInputStream fis = new FileInputStream(name);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//对class文件进行解密
cypher(fis,bos);
fis.close();
//获得字节数组
byte[] buf = bos.toByteArray();
bos.close();
//把字节数组传入defineClass()方法 返回一个Class文件
return defineClass(buf, 0, buf.length);
} catch (Exception e) {
e.printStackTrace();
}
return super.findClass(name);
}
}
public class ClassLoaderTest {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
//使用自定义加载器加载文件
// Class clazz = new MyClassLoader("bin\\test\\enhance\\classloader").loadClass("ClassLoaderAttachment");
Class clazz = new MyClassLoader("itcastlib").loadClass("ClassLoaderAttachment");
//这里不能用ClassLoaderAttachment类接收,因为现在classPath里的class文件是被加了密的。
Date date = (Date)clazz.newInstance();
System.out.println(date.getClass().getClassLoader());
System.out.println(date);
}
}
问题:
rt.jar中有java.lang.System类,我可不可以自己再写一个java.lang.System来用?
答:rt.jar本来有System类的,而加载的时候又有委托机制,也就是说会最先找最上级,按照普通的方式的话自己写的System类是没有机会被加载到的,但是我们可以撇开委托机制,用特殊方法写一个类加载器去加载