类加载器:
基本概念:
一般来说:java文件(源程序)经过编译器被转换成java字节码。类加载器负责读取字节码文件,并转换成java.lang.class的一个实例对象。每个这样的实例代表一个java类。通过实例的newInstance方法,就可以创建出该类一个对象。
Java.lang.ClassLoader类的介绍:
ClassLoader类的基本职责就是根据指定的类的名称,找到或生产对应的字节码,然后从这些字节码中定义出一个java类。即,java.lang.Class的一个实例。
常用方法:
LoadClass(String name);加载名称为name的类,返回结果是java.lang.Class的实例
findClass(String name):查找名称为name的已经被加载过的类,返回ava.lang.Class的实例。
defineClass(String name,byte[] b,int off,int,len);将字节数组b转成java类。
Java默认三个主要类加载器:
BootStrap,ExtClassLoader,AppClassLoader
BootStrap:用于加载其他类加载器。
类加载器之间的父子关系和管辖范围图
类加载器的委托机制:
每个类加载器加载类时,又先委托给其上级类加载器。(避免出现多字解码现象) 这就是委托机制。
问:当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?
如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。 但是类加器要去找上级的类加载,然后再找上一级累加器,
如果找不到,则返回发起者。发起者如果也找不到,则报异常,不会再找下一级。
自定义类加器步骤:
继承ClassLoader类。
复写findclass(String);
自定义类加载器的加载过程:
1.调用 findLoadedClass(String) 来检查是否已经加载类
2.委托给父类加载器,父类加载器调用loadClass 方法
3.loadClass调用调用 findClass(String) 方法查找类。
4.如果找不到,发起者再找。
如何实现父类加载器查找不到我们的文件呢?
类加载器必须在它字节的目录下才能加载。我们可以控制类文件存放的目录。
package cn.itcast; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class DemoCLassLoader extends ClassLoader{ public static void main(String[] args) throws Exception { String resPath = args[0];//需要被加密的文件。args[0]=D:\javaxue学习\test\src\cn\itcast\ClassLoaderDemo.java // String desPath = args[1];//加密后的文件存方法的路径名。 File file = new File(resPath); if(!file.exists()){throw new RuntimeException("文件不存在");} FileInputStream in = new FileInputStream(file); System.out.println("'fa"); //将加载后的文件扔保存到resPath的路径下。 int index = resPath.lastIndexOf("\\")+1; String filepath = resPath.substring(0,index);//获取路径名 File file1 = new File(filepath+"加密"+".class");//加密后存储文件。 System.out.println(file1); FileOutputStream os= new FileOutputStream(file1); cypher(in,os); } //加密 public static void cypher(InputStream in,OutputStream os) throws Exception{ int len = -1; while((len=in.read())!=-1){ os.write(len&255); } in.close(); os.close(); } //要加载的文件的路径 public DemoCLassLoader() { } private String dir; public DemoCLassLoader(String dir) { this.dir=dir; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { //使用类加载器并解密 :name是要加载的文件的名字 try { String path = dir+name+".class"; FileInputStream fis = new FileInputStream(path); //创建缓存 ByteArrayOutputStream fos = new ByteArrayOutputStream(); cypher(fis,fos); byte[] buf = fos.toByteArray(); //创建实例对象 System.out.println(new String(buf, 0, buf.length)); return defineClass(buf, 0, buf.length); } catch (Exception e) { e.printStackTrace(); } return super.findClass(name); } }