您的位置:首页 > 职场人生

黑马程序员——高新技术(类加载器)

2013-09-17 18:17 417 查看
------- android培训java培训、期待与您交流! ----------

类加载器:

1、java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap------>ExtClassLoader-------->AppClassLoader;

2、类加载器也是java类,因为其它是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器,就是BootStrap(不是java类)。

类加载器的委托机制:

当java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?

1、首先当前线程的类加载器去加载线程中的第一个类;

2、如果类A中引用了类B,java虚拟机将使用加载类A的类加载器来加载类B;

3、还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。

4、每个类加载器加载类时,又先委托给其上级类加载器(当所有祖宗类加载器没有加载到类,就回到发起者类加载器,如还加载不了,则抛ClassNotFoundException,而不是再去找发起者类加载器的的儿子)。

类加载器管辖范围:






获得类加载器实例:

public class ClassLoaderTest {
public static void main(String[] args)throws Exception {
System.out.println(ClassLoaderTest.class.getClassLoader().getClass()
.getName());//打印类加载器名字
System.out.println(System.class.getClassLoader());//打印System类的加载器
ClassLoader loader=ClassLoaderTest.class.getClassLoader();
while(loader!=null){//此处用于测试本类加载的时候到底有几个加载器,以及他们的层次结构
System.out.println(loader.getClass().getName());
loader=loader.getParent();
}
System.out.println(loader);
}
}


编写自己的类加载器步骤:

1、定义一个类继承ClassLoader类;

2、覆盖findClass方法,在覆盖过程中调用defineClass来创建实例类返回。

如下综合实例:编写自己的类加载器,并加密文件,这样就只能由自己的类加载器来进行加载
自己的类加载器:

package cn.itcast.day2;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
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];/*主函数参数,在运行时需输入主函数参数,如本例中需输入
E:\javaproject-test\javaEnhance\bin\cn\itcast\day2\ClassLoaderAttachment.class itcastlib*/
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);
}
}
String classDir;
@Override
//覆盖findClass方法
protected Class<?> findClass(String name)throws ClassNotFoundException{
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("my classloader");//用于测试是否是自己的类加载器进行加载的
byte[] bytes=bos.toByteArray();
return defineClass(bytes, 0, bytes.length);	//返回字节码文件
} catch (Exception e) {
System.out.println("流异常");
}
return super.findClass(name);
}
public MyClassLoader(){
}
public MyClassLoader(String classDir){//带参数的构造函数
this.classDir=classDir;
}
}

定义一个用于做加密测试的类:

package cn.itcast.day2;
import java.util.Date;
public class ClassLoaderAttachment extends Date {
@Override
public String toString(){
return "hello itcast";
}
}

定义一个主类,用于测试自己定义的类加载器是否正确:

package cn.itcast.day2;
import java.util.Date;
public class ClassLoaderTest {
public static void main(String[] args)throws Exception {
/*1、执行此步骤时,若先用加密后的文件ClassLoaderAttachment.class覆盖掉cn.itcast.day2下的ClassLoaderAttachment.class文件,则父类加载器加载此文件时就会报错,无法识别,因为已加密;
2、执行此步骤时,如先删掉cn.itcast.day2下的ClassLoaderAttachment.class文件,则父类加载器就无法找到,这时就会由自己定义的加载器进行加载。*/
Class clazz=new MyClassLoader("itcastlib").loadClass("cn.itcast.day2.ClassLoaderAttachment");
Date d1=(Date)clazz.newInstance();
System.out.println(d1);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息