-》简要介绍什么是累加器和类加载器的作用
-》java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:
BootStrap,ExtClassLoader,AppClassLoader
-》类加载器也是java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个加载器不是java类,这正是BootStrap
-》java虚拟机中的所有类装载器采用具有父子关系的属性结构进行
类加载器之间的父子关系和管辖范围图
父子关系:AppClassLoader->ExtClassLoader->BootStrap
关系范围:
BootStrap--->JRE/lib/rt.jar
ExtClassLoader--->JRE/lib/ext/*.jar
AppClassLoader--->CLASSPATH指定的所有jar或目录
类加载器的委托机制
-》当java虚拟机要加载一个类时,到底派出那个类加载器去加载呢?
-》》首先当前线程的类加载器去加载线程中的第一个类
-》》如果类A中引用了类B,java虚拟机将使用加载类A的类装载器来加载类B
-》》还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类
-》每个类加载器加载类时,又先委托给其上级类加载器
-》》当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加在不了,则抛出ClassNotFoundException,不是再去找发起者类加载的儿子,因为没有getChild方法,即使有,那有多个子类,找那个?
编写自己的类加载器
知识讲解
-》自定义的类加载器必须继承ClassLoader
-》loadClass方法与findClass方法,得到class文件转换成字节码
-》defineClass方法
编程步骤
-》编写一个对文件内容进行简单加密的程序
-》编写一个自己的类装载器,可实现对加密过的类进行装载和解密
-》编写一个程序调用类加载器加载类,在源程序中不能用该类名定义引用变量,因为编译器无法识别这个类,程序中可以除了使用ClassLoader.load方法之外,还可以使用设置线程的上下文类加载器或者系统类加载器,然后再使用Class.forName
实验步骤
-》对不带报名的class文件进行加密,加密结果存放到另外一个目录,例如:java MyClassLoader MyTest.class F:\itcast
-》运行加载类的程序,结果能够被正常加载,但打印出来的类装载器名称为AppClassLoader:java MyClassLoader MyTest F:\itcast
-》用加密后的类文件替换CLASSPATH环境下的类文件,再执行上一步操作就出问题了,错误说明是AppClassLoader类装载器装载失败
-》删除CLASSPATH环境下的类文件,再执行上一步操作就没问题了。
实例代码:
public class ClassLoaderAttachment extends Date {
public String toString(){
return "hello,itcast";
}
}
public class ClassLoaderTest {
/**
* @param args
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
System.out.println(
ClassLoaderTest.class.getClassLoader().getClass().getName()
);
System.out.println(
System.class.getClassLoader()
);
System.out.println("xxx");
ClassLoader loader = ClassLoaderTest.class.getClassLoader();
while(loader != null){
System.out.println(loader.getClass().getName());
loader = loader.getParent();
}
System.out.println(loader);
//System.out.println(new ClassLoaderAttachment().toString());
System.out.println("xxx2");
Class clazz = new MyClassLoader("itcastlib").loadClass("cn.itcast.day2.ClassLoaderAttachment");
Date d1 = (Date)clazz.newInstance();
System.out.println(d1);
}
}
public class MyClassLoader extends ClassLoader{
/**
* @param args
*/
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;
}
}
|