深入java虚拟机学习 -- 类的加载机制(四)
类加载的命名空间
每个类加载器都有自己的命名空间,命名空间由所有以此加载器为初始类加载器的类组成,不同命名空间的两个类是不可见的,但只要得到类所对应的Class对象的refrence(反射),还是可以访问另一个命名空间的类信息的。
同一个命名空间内的类是相互可见的,子加载器的命名空间包含所有父加载器的命名空间,也就是说由子加载器加载的类能看到父加载器加载的类。例如:系统类加载器加载的类能看到根类加载器加载的类(用户自定的类可以访问java.lang.*包下的信息),由父加载器加载的类不能看到子加载器加载的类。
如果两个加载器之间没有直接或者间接的父子关系,那么它们个字加载的类相互不可见。
创建用户自定义的类加载器
要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,该方法根据参数指定的类的名字,返回对应的Class对象的引用。
protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); }
我们可以按到ClassLoader里面的findClass方法的默认实现会抛出ClassNotFoundException异常,我们只需要在自定义的加载器里面重写,即可。
public class MyClassLoader extends ClassLoader { private String name;//类加载器的名字 private String path="";//加载类的默认路径 private String fileType=".class"; //class文件的扩展名 public MyClassLoader(String name){ super();//让系统类加载器成为该类加载器的父加载器 this.name=name; } public MyClassLoader(ClassLoader parent,String name){ super(parent);//显示指定该类加载器的父加载器 this.name=name; } @Override public String toString() { return this.name; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } /** * 抽象类ClassLoader的findClass函数默认是抛出异常的。而前面我们知道, * loadClass在父加载器无法加载类的时候,就会调用我们自定义的类加载器中的findeClass函数, * 因此我们必须要在loadClass这个函数里面实现将一个指定类名称转换为Class对象. * @param name * @return */ @Override protected Class<?> findClass(String name) { byte [] data=this.loadClassData(name); return this.defineClass(name,data,0,data.length); } private byte[] loadClassData(String name) { InputStream is=null; byte [] data=null; ByteArrayOutputStream baos=null; try { this.name=this.name.replace(".","\\"); is=new FileInputStream(new File(path+name+fileType)); baos=new ByteArrayOutputStream(); int ch=0; while(-1!=(ch=is.read())){ baos.write(ch); } data= baos.toByteArray(); } catch(Exception e){ e.printStackTrace(); } finally { try { is.close(); baos.close(); } catch(IOException e) { e.printStackTrace(); } } return data; } public static void main(String[] args) throws Exception { MyClassLoader loader1 = new MyClassLoader("loader1");//没有指定loader的父加载器,则默认的父加载器为系统类加载器 loader1.setPath("G:\\myapp\\loader1\\"); MyClassLoader loader2 = new MyClassLoader(loader1,"loader2");//指定loader2的父加载器为loader1,这里的loader1和loader2都为MyClassLoader的实例 loader2.setPath("G:\\myapp\\loader2\\"); MyClassLoader loader3 = new MyClassLoader(null,"loader3");//bootstrap类加载器 loader3.setPath("G:\\myapp\\loader3\\"); //test(loader1); test(loader2); test(loader3); } public static void test(ClassLoader loader) throws Exception { Class clazz=loader.loadClass("Sample"); Object object=clazz.newInstance(); }
开开心心编码,快快乐乐生活。