Java类加载机制;
为啥叫双亲委派?爹妈分别是谁?
The ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader. When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself. The virtual machine's built-in class loader, called the "bootstrap class loader", does not itself have a parent but may serve as the parent of a ClassLoader instance.
jdk中根本没说爹妈的事情,就是一个delegation的事情,
delegation 英[ˌdelɪˈgeɪʃn] 美[ˌdɛlɪˈɡeʃən] n. 授权; 委派; 代表(团);
bootstrap - jre/lib/rt.jar
extclassLoader-jre/lib/ext/*.jar
appClassLoader-classpath指定
myClassLoader-自己指定的;
学习了:http://blog.csdn.net/csh624366188/article/details/8096989 这个大神膜拜一下!
http://blog.csdn.net/yangxin_blog/article/details/48214857
需要对程序做一点点修改,源码如下:
package com.stono.jvm; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; public class MyClassLoader extends ClassLoader { private String name; // 类加载器的名字 private String path = "d:\"; // 加载类的路径 private final 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; } /** * @param 类文件的名字 * @return 类文件中类的class对象 * * 在这里我们并不需要去显示的调用这里的findclass方法,在上篇文章中,我们通过查看 * loadclass的源码可以发现,她是在loadclass中被调用的,所以这里我们只需重写这个方法, * 让它根据我们的想法去查找类文件就ok,他会自动被调用 * * * defineClass()将一个 byte 数组转换为 Class 类的实例。必须分析 Class,然后才能使用它 * 参数: * name - 所需要的类的二进制名称,如果不知道此名称,则该参数为 null * b - 组成类数据的字节。off 与 off+len-1 之间的字节应该具有《Java Virtual Machine Specification》定义的有效类文件的格式。 * off - 类数据的 b 中的起始偏移量 * len - 类数据的长度 */ @Override protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] data = this.loadClassData(name); // 获得类文件的字节数组 return this.defineClass(name, data, 0, data.length); } /** * * @param 类文件的名字 * @return 类文件的 字节数组 * 通过类文件的名字获得类文件的字节数组,其实主要就是用 * 输入输出流实现。 */ private byte[] loadClassData(String name) { InputStream is = null; byte[] data = null; ByteArrayOutputStream baos = null; try { this.name = this.name.replace(".", "\"); String replaceAll = name.replace(".", "\"); // 注意这块修改了一下 is = new FileInputStream(new File(path+replaceAll+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 (Exception e2) { e2.printStackTrace(); } } return data; } public static void main(String[] args) throws Exception { MyClassLoader loader1 = new MyClassLoader("loader1"); loader1.setPath("D:\myapp\serverlib\"); MyClassLoader loader2 = new MyClassLoader(loader1, "loader2"); loader2.setPath("D:\myapp\clientlib\"); MyClassLoader loader3 = new MyClassLoader(null,"loader3"); loader3.setPath("D:\myapp\otherlib\"); test(loader1); System.out.println("-------------"); test(loader2); System.out.println("-------------"); test(loader3); Object object = loader2.loadClass("Simple").newInstance(); System.out.println(object instanceof Simple); Object object1 = loader1.loadClass("com.stono.jvm.Simple").newInstance(); System.out.println(object1 instanceof Simple); // true 了 Object object2 = loader2.loadClass("com.stono.jvm.Simple").newInstance(); System.out.println(object2 instanceof Simple); // true 了 Object object3 = loader3.loadClass("com.stono.jvm.Simple").newInstance(); System.out.println(object3 instanceof Simple); // false 了 } private static void test(MyClassLoader loader) throws Exception { Class<?> clazz = loader.loadClass("com.stono.jvm.Simple"); System.out.println(clazz.getClassLoader()); } }
直接重构com.stono.jvm.ClassLoaderTest.main(...).new ClassLoader() {...}.findClass(String)方法好像是没有效果,
没有效果的源码如下:可能是jdk版本变了,当前使用了jdk1.8;
package com.stono.jvm; import java.io.IOException; import java.io.InputStream; public class ClassLoaderTest { public static void main(String[] args) throws Exception { // 匿名内部类实现自定义类加载器 ClassLoader myClassLoader = new ClassLoader() { @Override protected Class<?> findClass(String name) throws ClassNotFoundException { // 获取类文件名 String filename = name.substring(name.lastIndexOf("."+1))+".class"; InputStream in = getClass().getResourceAsStream(filename); if(in == null){ throw new RuntimeException("Could not found class file:"+filename); } byte[] b = null; try { b = new byte[in.available()]; } catch (IOException e) { e.printStackTrace(); } return defineClass(name, b, 0,b.length); } }; // 好像是自己定义的类加载机制,结果没有效果呀; Object obj = myClassLoader.loadClass("com.stono.jvm.ClassLoaderTest").newInstance(); System.out.println(obj.getClass().getClassLoader()); System.out.println(ClassLoaderTest.class.getClassLoader()); System.out.println(obj instanceof ClassLoaderTest); } }
学习了:http://blog.csdn.net/p10010/article/details/50448491
由于不能引用默认包中的类,所以需要进行代包的文件的编写,稍微麻烦一些;
不过可以通过自己定义的classLoader发现声明的类不是系统加载的类,!