- 知识讲解
- 自定义的类加载器必须继承ClassLoader
- loadClass方法与findClass方法
- defineClass方法
- 编程步骤
- 编写一个对文件内容进行简单加密的程序。
- 编写一个自己的类加载器,可实现对加密过得类进行加载和解密。
- 编写一个程序调用类加载器加载类,在源程序中不能用该类名定义引用变量,因为编译器无法识别这个类。程序中可以除了使用ClassLoader.load方法之外,还可以使用设置线程的上下文类加载器或者系统类加载器,然后再使用Class.forName。
- 实验步骤:
- 对不带包名的class文件进行加密,加密结果存放到另外一个目录,例如:java MyClassLoader MyTest.class F:itcast
- 运行加载类的程序,结果能够被正常加载,但打印出来的类装载器名称为AppClassLoader:java MyClassLoader MyTest F:itcast
package com.itcast.day3; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; /** * 1 加载 * 2 加密 * 3 自定义类加载 * @author hp * */ public class MyClassLoader extends ClassLoader{ public static void main(String[] args) throws Exception{ String srcPath=args[0]; String destDir=args[1]; //加载.class,加密.class,写到自定义目录 FileInputStream fis=new FileInputStream(srcPath); String destPath=destDir+"\"+srcPath.substring(srcPath.lastIndexOf("\")); FileOutputStream fos=new FileOutputStream(destPath); cyp(fis,fos); fis.close(); fos.close(); } /** * 加密 or 解密 * @param ips * @param ops * @throws Exception */ private static void cyp(InputStream ips,OutputStream ops)throws Exception{ int b=-1; while((b=ips.read())!=-1){ ops.write(b^0xff); } } private String fileDir;//.class文件路径 /** * 自定义类加载 */ @Override protected Class<?> findClass(String name) throws ClassNotFoundException { String classFileName=fileDir+"\"+name+".class"; try { FileInputStream fis=new FileInputStream(classFileName); ByteArrayOutputStream bos=new ByteArrayOutputStream(); cyp(fis,bos); fis.close(); byte[] bytes=bos.toByteArray(); return defineClass(bytes, 0, bytes.length); } catch (Exception e) { e.printStackTrace(); } return super.findClass(name); } public MyClassLoader(){ } public MyClassLoader(String fileDir){ this.fileDir=fileDir; } }
package com.itcast.day3; import java.util.Date; /** * 要加载的类 * @author liujl *继承自Date是因为方便接收newInstance返回值,不然写成ClassLoaderAttachment自己时,编译不通过(加密过) */ public class ClassLoaderAttachment extends Date { @Override public String toString(){ return "hello itcast"; } }
package com.itcast.day3; import java.util.Date; /** * 类加载器测试 * @author ljl * */ public class ClassLoaderTest { public static void main(String[] args)throws Exception { /** * 01.逐一编写下列代码,说明放置在不同位置的类确实由不同的类加载器加载的。 */ //sun.misc.Launcher$AppClassLoader System.out.println(ClassLoaderTest.class.getClassLoader() .getClass().getName()); //Exception in thread "main" java.lang.NullPointerException //报空指针,说明 ClassLoaderTest和System 这两个类实际存放位置不同,也确实不是同一个类加载器加载的 //System是由BootStrap加载的 // System.out.println(System.class.getClassLoader().getClass().getName()); //null ,类加载器为null说明,不存在类加载器的java类实例,那么System一定是由jvm的核心加载器BootStrap负责加载 System.out.println(System.class.getClassLoader()); /** * 02.查看类加载器的层次结构关系 */ System.out.println(" *******查看类加载器的层次结构关系"); ClassLoader loader=ClassLoaderTest.class.getClassLoader(); while(loader!=null){ System.out.println(loader.getClass().getName()); loader=loader.getParent(); } System.out.println(loader); /**运行结果 * sun.misc.Launcher$AppClassLoader---孙子 sun.misc.Launcher$ExtClassLoader---爸爸 null--爷爷--BootStrap */ /** * 03.使用自己定义的类加载器加载特定目录下的类 */ //System.out.println(new ClassLoaderAttachment().toString()); Class clazz=new MyClassLoader("itcastlib").loadClass("ClassLoaderAttachment"); Date d1=(Date)clazz.newInstance(); System.out.println(d1); } }