ClassLoader笔记

参考视频:

系统学习让你轻松定义java类加载器_哔哩哔哩_bilibili

本文代码:

GitHub - CodePpoi/classloader-learn

参考博客:

视频学习笔记 | 系统学习让你轻松定义 Java 类加载器 · 语雀

随便写写,通过loadClass方法来加载,先看该ClassLoader是否有父类,有则递归调用父类的loadClass,父类能加载则直接返回父类加载的结果,如果父类无法加载,则调用自身的findClass方法:

不同加载器加载的同一个类,两者不相等

package com.company;

import java.io.IOException;
import java.io.InputStream;

public class ClassLoaderTest {

    public static void main(String[] args) throws Exception {
        ClassLoader myLoader = new ClassLoader() {
            @Override
            public Class<?> loadClass(String name) throws ClassNotFoundException {
                try {
                    String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
                    InputStream is = getClass().getResourceAsStream(fileName);
                    if (is == null) {
                        return super.loadClass(name);
                    }
                    byte[] b = new byte[is.available()];
                    is.read(b);
                    return defineClass(name, b, 0, b.length);
                } catch (IOException E) {
                    throw  new ClassNotFoundException();
                }
            }
        };
        Object obj = myLoader.loadClass("com.company.ClassLoaderTest").newInstance();

        System.out.println(obj.getClass());
        System.out.println(obj instanceof com.company.ClassLoaderTest);
    }
}
loadClass()、findClass()、defineClass()区别见https://www.jianshu.com/p/b75a89014e27

从名字就可以看出来,load是加载,find是找到class文件(我的理解就是从文件路径读取文件,然后转换成字节流或者说字节数组,然后字节流作为入参传入defineClass方法),然后define是把class文件转换成类(Class),自定义类加载器一般覆盖findClass方法

字节码文件就是 .class,这个文件是加载到JVM虚拟机的方法区,加载到方法区的内容,可参考IDEA使用jclasslib-bytecode-viewer插件查看字节码_newbaby2012的专栏-CSDN博客

我们也是根据方法区的字节码,来创建对应类的Class对象的,就是比如 sample.Class 对象

类加载器三个阶段

1.  加载

把.class文件加载到方法区

2.  连接

分为3小部分

a 验证 验证当前文件对JVM虚拟机是安全的,不会导致其崩溃

b 准备 对静态static变量分配内存,并赋默认值(非初始值,int 默认值为0,但你可能这么定义了static int a = 5,在这个阶段只会把a设置成0。赋值为5的操作是初始化时做)

c 解析 

3. 初始化

加载器

Java自带加载器:

根类加载器BootStrap,没有继承任何加载器,使用c++编写

扩展类加载器Extension,继承自BootStrap,使用java编写,

系统类加载器AppClassLoader,也叫应用加载器,继承自Extension,用户自定义的类加载器的默认父加载器,就是比如你在你的Project里面加了一个Demo.Java文件,那么Demo.class.getClassLoader()得到的就是AppClassLoader

package com.company;

import sun.net.spi.nameservice.dns.DNSNameService;

import java.io.File;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;

public class Main {

    public static void main(String[] args) throws Exception {
        // BootStrap加载器,C++编写,加载<JAVA_HOME>\jre\lib里面的类库(比如rt.jar,rt是runtime的简称)
        ClassLoader classLoader = Object.class.getClassLoader();
        System.out.println(classLoader); // 打印null

        classLoader = Number.class.getClassLoader();
        System.out.println(classLoader); // 打印null

        //Extension加载器,纯java编写,ExtClassLoader,加载<JAVA_HOME>\jre\lib\ext里面的类库(比如dnsns.jar)或者系统变量"java.ext.dirs"指定目录下面的类
        ClassLoader classLoader1 = DNSNameService.class.getClassLoader();
        System.out.println(classLoader1);


        //System加载器,纯java编写,AppclassLoader,我们写的java程序一般由这个加载
        ClassLoader classLoader2 = Main.class.getClassLoader();
        System.out.println(classLoader2);

        MyFileClassLoader classLoader3 = new MyFileClassLoader("");
        Class<?> clazz = classLoader3.loadClass("com.company.Demo");
        clazz.newInstance();
        //自己定义的类,默认继承AppClassLoader
        System.out.println(clazz.getClassLoader());

//        File file = new File("d:/");
//        URI uri = file.toURI();
//        URL url = uri.toURL();
//
//        URLClassLoader classLoader3 = new URLClassLoader()

    }
}

 Java虚拟机按需加载,只有当用到该类时,才会将它的class文件(class文件在编译时生成)加载到虚拟机内存,并生成class对象


package com.company;


// 1. 继承ClassLoader
// 2. 覆盖 findClass方法
public class MyFileClassLoader extends ClassLoader {

    private String directory; // 被加载类所在的目录

    public MyFileClassLoader(String directory) { // 默认父类加载器就是系统类加载器 AppClassLoader
        this.directory = directory;
    }

    public MyFileClassLoader(ClassLoader parent, String directory) {
        super(parent);
        this.directory = directory;
    }


}

URLClassLoader 

扩展了ClassLoader,从指定URL地址(这个地址可以指向磁盘,也可以指向网络地址),用我们指定的classLoader加载

显示加载和隐式加载

显示 调用class.ForName和loadClass来加载

隐式 不需要调用上面的方法,而是java虚拟自动装载到内存,比如Demo.java文件中有代码 new Demo2(),那么在加载Demo.class的时候会自动加载Demo2.class到虚拟机内存中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值