类加载器与双亲委派模型

2 篇文章 0 订阅
1 篇文章 0 订阅

一.类加载器:根据指定的全限定名将class文件加载到JVM内存,转为class对象。从JVM角度看,分为两种类加载器:

1.启动类加载器(Bootstrap ClassLoader)

由C++语言实现(针对HotSpot),负责将存放在<JAVA_HOME>\lib目录或-Xbootclasspath参数指定的路径中的类库加载到内存中。

2.其他类加载器:

由Java语言实现,继承自抽象类ClassLoader。如:
    2.1 扩展类加载器(Extension ClassLoader):负责加载<JAVA_HOME>\lib\ext目录或java.ext.dirs系统变量指定的路径中的所有类库。
    2.2 应用程序类加载器(Application ClassLoader):负责加载用户类路径(classpath)上的指定类库,我们可以直接使用这个类加载器。一般情况,如果我们没有自定义类加载器默认就是用这个加载器。

二.双亲委派模型

如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。
每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时(即ClassNotFoundException),子加载器才会尝试自己去加载。抽象类java.lang.ClassLoader的loadClass(String, boolean)方法实现双亲委派模型:
1.首先,检查一下指定名称的类是否已经加载过,如果加载过了,就不需要再加载,直接返回。
2.如果此类没有加载过,那么,再判断一下是否有父加载器;如果有父加载器,则由父加载器加载(即调用parent.loadClass(name, false);),否则调用Bootstrap类加载器来加载。
3.如果父加载器及bootstrap类加载器都没有找到指定的类,那么调用当前类加载器的findClass方法来完成类加载。
4.抽象类java.lang.ClassLoader的findClass(String)方法默认抛出ClassNotFoundException异常,所以自定义类加载器必须重写findClass(String)方法。

三.编写自定义类加载器

1.首先写两个简单的类用于测试

在IDEA里新建java工程,创建如下包

Demo1.java

package com.classloader;

public class Demo1 {

    public Demo1(){
        System.out.println("Demo1由" + getClass().getClassLoader().getClass() + "加载");
    }

    public void hello(){
        System.out.println("hello Demo1");
    }
}

 

Demo2.java

package com.classloader;

public class Demo2 {

    public Demo2(){
        System.out.println("Demo2由" + getClass().getClassLoader().getClass() + "加载");
    }

    public void hello(){
        System.out.println("hello Demo2");
    }
}

两个demo编译后,将Demo2.class从项目输出目录下拷贝到本地磁盘D:/test/com/classloader/下,并从项目输出目录中删除

创建自定义类加载器

package com.classloader;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @desc: 自定义类加载器
 * @date: 2018/7/23 19:29
 */
public class MyClassLoader extends ClassLoader {

    /**
     * 类加载路径
     */
    private String path;

    public MyClassLoader(String path) {
        this.path = path;
    }

    /**
     * @desc: 重写findClass方法用于加载指定类
     * @date: 2018/7/23 17:47
     * @param:
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] data = readFileToByte(name);
        return defineClass(name, data, 0, data.length);
    }

    /**
     * @desc: 读取class文件转换为字节数组
     * @date: 2018/7/23 17:46
     * @param:
     */
    private byte[] readFileToByte(String name) {
        InputStream is = null;
        byte[] result = null;
        //将全限定类名
        name = name.replaceAll("\\.", "/");
        String classPath = path + name + ".class";
        File file = new File(classPath);
        ByteArrayOutputStream os = new ByteArrayOutputStream();

        try {
            is = new FileInputStream(file);
            int tmp = 0;
            while ((tmp = is.read()) != -1) {
                os.write(tmp);
            }
            result = os.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (os != null) {
                    os.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return result;
    }

    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        MyClassLoader classload = new MyClassLoader("D:/test/");
//        com.classloader.Demo1
        Class clazz = classload.loadClass("com.classloader.Demo1");
        Object obj = clazz.newInstance();
        Method hello = clazz.getDeclaredMethod("hello", null);
        hello.invoke(obj, null);
    }
}

执行main方法

从控制台输出可以看出,Demo1.class是由AppClassLoader类加载器加载的。

将main方法中指定的全限定类名改为com.classloader.Demo2

再次执行main方法

可以看出Demo2.class是由我们自己编写的自定义类加载器加载的

 

原文参考:https://www.cnblogs.com/wxd0108/p/6681618.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值