Loading

Java类加载机制

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发现声明的类不是系统加载的类,!

 

posted @ 2018-01-06 18:21  stono  阅读(177)  评论(0编辑  收藏  举报