类加载器(class loader)用来加载 Java 类到 Java 虚拟机中,虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块被称为“类加载器”。
一般来说,Java 虚拟机使用Java类的方式如下:Java源程序(.java文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。实际的情况可能更加复杂,比如 Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。为了更好的理解类的加载机制,我们先来看看类加载器中几个重要的方法:
loadClass()方法:加载器的总调度方法。它会根据加载器双亲委派机制来选择适当的加载器加载出指定类名称的Class实例
findClass()方法:读取class文件形成一个字节数组,然后将该字节数组传递给 defineClass方法,试着导入这个类型,返回一个Class实例
defineClass方法:根据传入的资源,调用本地方法进行具体的类的加载过程。加载成功会返回一个Class实例
所要干的事情就是要覆盖findClass()(让它去加载我们要的类.class,就是专门自己干),为什么不覆盖loadClass()?是因为保留双亲委派的那个流程。
- package cn.itcast.cl;
- 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{
- /**把源目录下的二进制文件加密,生成到itcastlib下
- * @param args
- * 源路径G:\Users\king\eclipsespace\classloader\bin\cn\itcast\loadedclass\Attachment.class
- * dest:itcastlib
- */
- 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;//类所在的路径
- public MyClassLoader(){
-
- }
- public MyClassLoader(String classDir){
- this.classDir = classDir;
- }
- //传入类名,loadClass()会调用这个findClass,所以我们只复写findClass()
- @Override
- 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("aaa");
- byte[] bytes = bos.toByteArray();
- return defineClass(bytes, 0, bytes.length);//传入字节数组返回一个类
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return super.loadClass(name);
- }
- }
- package cn.itcast.loadedclass;
- import java.util.Date;
- public class Attachment extends Date
- {
- public String toString(){
- return "hello,itcast";
- }
- }
- package cn.itcast.cl;
- import java.util.Date;
- //import cn.itcast.loadedclass.Attachment;注释掉,类加载解释不了啊
- public class CLTest
- {
- public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAcces***ception
- {
- System.out.println(CLTest.class.getClassLoader().getClass().getName());
- System.out.println("C++ bootstrap "+System.class.getClassLoader());
- System.out.println("xxx");
- ClassLoader loader = CLTest.class.getClassLoader();
- while(loader != null){
- System.out.println(loader.getClass().getName());
- loader = loader.getParent();
- }
- System.out.println("循环递归向上寻找: "+loader+"\n");
-
- Class clazz=new MyClassLoader("itcastlib").loadClass("Attachment");
- //编译不过,Attachment不能被加载器加载,因为还没解密
- /*Attachment cannot be resolved to a type
- Attachment a=(Attachment)clazz.newInstance();
- System.out.println("解过密: "+a.toString());*/
-
- Date d = (Date) clazz.newInstance();;
- //父类能正常被类加载器加载,这就是Attachment继承Date的用途
- System.out.println("解过密: "+ d.toString());
-
- }
- }
阅读(1594) | 评论(0) | 转发(0) |