我们先写一个URLClassLoader的子类,这样我们就可以用定义在其中的一些protected方法了.
/* * Test6.java * * Created on 2007-9-24, 10:57:57 * * To change this template, choose Tools | Templates * and open the template in the editor. */ package test1; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.logging.Level; import java.util.logging.Logger; /** * * @author hadeslee */ @SuppressWarnings(value = "unchecked") public class Test6 extends URLClassLoader { public Test6() { super(new URL[0]); Thread.currentThread().setContextClassLoader(this); ClassLoader cl = this.getClass().getClassLoader(); if (cl instanceof URLClassLoader) { URLClassLoader loader = (URLClassLoader) cl; URL[] urls = loader.getURLs(); for (URL u : urls) { System.out.println(u); this.addURL(u); } } } //根据类的全限定名得到类的字节数组 private byte[] getClassData(String name) { try { InputStream is = this.getClass().getResourceAsStream(getPathName(name)); byte[] temp = new byte[is.available()]; is.read(temp); is.close(); return temp; } catch (IOException ex) { Logger.getLogger(Test6.class.getName()).log(Level.SEVERE, null, ex); return null; } } //要隐藏的类 private void hideClasses(String className) { DataOutputStream dout = null; try { dout = new DataOutputStream(new FileOutputStream("hide.dat")); for (String s : className) { dout.writeUTF(s); byte[] data = this.getClassData(s); dout.writeInt(data.length); dout.write(data); } } catch (IOException ex) { Logger.getLogger(Test6.class.getName()).log(Level.SEVERE, null, ex); } finally { try { dout.close(); } catch (IOException ex) { Logger.getLogger(Test6.class.getName()).log(Level.SEVERE, null, ex); } } } private Class findClass0(String className){ DataInputStream din = null; try { din = new DataInputStream(new FileInputStream("hide.dat")); while (true) { String name = din.readUTF(); System.out.println("find name=" + name); int length = din.readInt(); byte[] data = new byte[length]; din.read(data); if (name.equals(className)) { return this.defineClass(name, data, 0, length); } } } catch (IOException ex) { Logger.getLogger(Test6.class.getName()).log(Level.SEVERE, null, ex); } catch (ClassFormatError classFormatError) { } finally { try { if (din != null) { din.close(); } } catch (Exception exe) { exe.printStackTrace(); } } return null; } protected Class findClass(String className) throws ClassNotFoundException { Class c=this.findClass0(className); if(c==null){ return super.findClass(className); }else{ return c; } } //根据类名得到完整的加载路径名 private String getPathName(String name) { StringBuilder sb = new StringBuilder(); String[] names = name.split("\\."); for (String s : names) { sb.append("/").append(s); } sb.append(".class"); return sb.toString(); } public static void main(String[] args) throws Exception { Test6 t = new Test6(); t.hideClasses("test2.A", "test2.B"); Class c = t.findClass("test2.B"); Object o = c.newInstance(); test2.B b=(test2.B)o; Method m = c.getDeclaredMethod("print", String.class); m.invoke(o, "我是中国人"); System.out.println(c); } } 以下是A和B类的代码 /* * A.java * * Created on 2007-9-24, 10:26:47 * * To change this template, choose Tools | Templates * and open the template in the editor. */ package test2; /** * * @author hadeslee */ public class A { private int index=10; public void doSth(){ } } /* * B.java * * Created on 2007-9-24, 10:29:04 * * To change this template, choose Tools | Templates * and open the template in the editor. */ package test2; /** * * @author hadeslee */ public class B extends A{ public void print(String s){ System.out.println(s); } }
此程序的实现思路是:先写一个继承自URLClassLoader的类加载器,然后我们要类的时候,就从这个类加载器去加载,我们要隐藏类的时候,也是由这个类加载器去实现隐藏, 其实隐藏就是把很多类放到一个文件里面去,然后加上自己的IO写法,然后在需要的时候,又可以又自己写进去的方法,把类的字节数组读出来,把它还原成一个类.在这里我们还需要重写一个方法,那就是定义在ClassLoader里面的findClass(String name)的方法,让它在找类的时候,不要乱找,而是用我们自己的方法来找,当我们自己的方法找不到的时候,才由它来找,这样的话,就可以实现先找我们自己的方式隐藏的类,再找一般情况下面的类.
对于类的加载,有很多东西是可以研究和学习的,希望在以后的学习过程中,能够慢慢了解它.
查看原文