自定义类加载器及双亲委派机制验证

自定义类加载器

项目结构

准备一个User类和MyClassLoader类,项目结构如下
在这里插入图片描述

MyClassLoader代码

package com.cwf.resource.jvm;

import java.io.FileInputStream;

public class MyClassLoader extends ClassLoader {
    // 自定义加载路径
    private String classPath;
    //构造方法,初始化加载路径
    public MyClassLoader( String classPath) {
        this.classPath = classPath;
    }

    /*
    在自定义路径下,加载字节码文件到内存中
     */
    private byte[] loadByte(String className) throws Exception{
        className=className.replaceAll("\\.","/");
        FileInputStream fis=new FileInputStream(classPath+"/"+className+".class");
        int len=fis.available();
        byte[] data= new byte[len];
        fis.read(data);
        fis.close();
        return data;
    }

    /*
    重写findClass方法
     */
    protected Class<?> findClass(String name)throws ClassNotFoundException {
        try {
            byte[] data = loadByte(name);
            //defineClass这个方法会将一个字节数组转为Class对象。
            return defineClass(name, data, 0, data.length);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ClassNotFoundException();
        }
    }
    
	//在main方法中调用loadClass方法去加载User类
    public static void main(String[] args) throws Exception {
        MyClassLoader loader = new MyClassLoader("F:\\class");
        Class<?> userClass = loader.loadClass("com.cwf.resource.jvm.User");
        System.out.println(userClass.getClassLoader().getClass().getName());
    }
}

将User.class文件拷贝一份到我们定义的路径中,然后执行main()方法
在这里插入图片描述

main方法执行结果

在这里插入图片描述

我们可以看到虽然我们使用的我们自定义的类加载器去加载我们的类但是最中加载User类的却是AppClassLoader,这就是由于双亲委派机制的原因。

指定自定义类加载器parent源码分析

自定义类加载器是何时指定parent的呢?

在调用MyclassLoader的构造方法前会先调用ClassLoader的构造方法 ClassLoader() , ClassLoader() 又调用了ClassLoader(Void unused, ClassLoader parent)这个有参构造方法,传入的parent参数就是通过getSystemClassLoader()方法获取的系统默认类加载器,

所以就指定了我们MyClassLoader的parent为AppClassLoader

   protected ClassLoader() {
        this(checkCreateClassLoader(), getSystemClassLoader());
    }
private ClassLoader(Void unused, ClassLoader parent) {
        this.parent = parent;
        if (ParallelLoaders.isRegistered(this.getClass())) {
            parallelLockMap = new ConcurrentHashMap<>();
            package2certs = new ConcurrentHashMap<>();
            domains =
                Collections.synchronizedSet(new HashSet<ProtectionDomain>());
            assertionLock = new Object();
        } else {
            // no finer-grained lock; lock on the classloader instance
            parallelLockMap = null;
            package2certs = new Hashtable<>();
            domains = new HashSet<>();
            assertionLock = this;
        }
    }

接下来我们删掉项目中的User类再执行一次main()方法,执行结果如下
在这里插入图片描述
说明如果父 类加载器指定路径下没有同名的类最中会由子类加载器自己加载

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值