Java 类加载器(一)

Java默认提供的三个ClassLoader

BootStrap ClassLoader

BootStrap ClassLoader称为启动类加载器。用来加载JDK核心类库。来看一下,BootStrap ClassLoader类加载器从哪些地方加载了相关的jar或class文件

URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
for (URL url : urls) {
    System.out.println(url);
}

执行结果如下:

file:/C:/Program%20Files/Java/jdk1.8.0_111/jre/lib/resources.jar
file:/C:/Program%20Files/Java/jdk1.8.0_111/jre/lib/rt.jar
file:/C:/Program%20Files/Java/jdk1.8.0_111/jre/lib/sunrsasign.jar
file:/C:/Program%20Files/Java/jdk1.8.0_111/jre/lib/jsse.jar
file:/C:/Program%20Files/Java/jdk1.8.0_111/jre/lib/jce.jar
file:/C:/Program%20Files/Java/jdk1.8.0_111/jre/lib/charsets.jar
file:/C:/Program%20Files/Java/jdk1.8.0_111/jre/lib/jfr.jar
file:/C:/Program%20Files/Java/jdk1.8.0_111/jre/classes

上述结果也可以通过查找sun.boot.class.path这个系统属性所得知

System.out.println(System.getProperty("sun.boot.class.path"));

Extension ClassLoader

Extension ClassLoader称为拓展类加载器。负责加载Java的拓展类库;默认情况下,加载JAVA_HOME/jre/lib/ext/目录下的所有jar

App ClassLoader

App ClassLoader称为系统类加载器,负责加载应用程序classpath目录下所有的jar和class文件

获取某个类由哪个类加载器加载

class Member {}
public class TestDemo {
    public static void main(String[] args) {
        Class<?> cls = Member.class;
        System.out.println(cls.getClassLoader());
        System.out.println(cls.getClassLoader().getParent());
        System.out.println(cls.getClassLoader().getParent().getParent());
    }
}

上面代码的运行结果

sun.misc.Launcher$AppClassLoader@232204a1
sun.misc.Launcher$ExtClassLoader@74a14482
null

下面的代码纯属演示,演示loadClass(String className)方法,没有实际意义

class Member {
    @Override
    public String toString() {
        return "Member{}";
    }
}
public class TestDemo {
    public static void main(String[] args) throws Exception{
        System.out.println(Class.forName("cn.cecurio.load.Member").
            getClassLoader().loadClass("cn.cecurio.load.Member").newInstance());
    }
}

自定义类加载器,加载本机文件

自定义的ClassLoader都必须继承自java.lang.ClassLoader类。Extension ClassLoaderApp ClassLoader都继承java.lang.ClassLoader类。但是Bootstrap ClassLoader不继承自java.lang.ClassLoader,因为它不是一个普通的Java类,底层由C++编写,已嵌入到了JVM内核当中,当JVM启动后,Bootstrap ClassLoader也随着启动,负责加载完核心类库后,并构造Extension ClassLoaderApp ClassLoader类加载器。

第一步: 在本机非项目CLASSPATH位置新建.java文件,并编译

名称是Member.java,内容如下:

package cn.cecurio.vo;

public class Member {
    public String toString() {
        return "Member in cn.cecurio.vo";
    }
}

第二步: 定义自己的类加载器

public class MyClassLoader extends ClassLoader {
    /**
     * 实现一个自定义的类加载器,传入类的全限定名,通过读取指定文件来加载类
     * @param className
     * @return 类的Class对象
     */
    public Class<?> loadData(String className) {
        // 加载类文件的数据信息
        byte[] classData = this.loadClassData();
        return super.defineClass(className,classData,0,classData.length);
    }

    /**
     * 通过指定类的文件路径,进行类的加载,其实就是读取二进制文件
     * @return 类文件的数据信息
     */
    private byte[] loadClassData() {
        try {
            File inFile = new File("D:" + File.separator + "tmp"
                + File.separator + "Member.class");
            InputStream inputStream = new FileInputStream(inFile);

            // 可以有一个方法取得所有的字节内容
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            // 定义读取的缓冲区
            byte[] data = new byte[512];
            int len = 0;
            while ((len = inputStream.read(data)) != -1) {
                bos.write(data,0,len);
            }

            byte[] ret = bos.toByteArray();
            inputStream.close();
            bos.close();
            return ret;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}

可以自己修改上述代码中,文件路径硬编码的地方

测试自己的类加载器

public class Main {
    public static void main(String[] args) {
        MyClassLoader loader = new MyClassLoader();
        Class<?> cls = loader.loadData("cn.cecurio.vo.Member");
        try {
            System.out.println(cls.newInstance());
            System.out.println(cls.getClassLoader());
            System.out.println(cls.getClassLoader().getParent());
            System.out.println(cls.getClassLoader().getParent().getParent());
            System.out.println(cls.getClassLoader().getParent().getParent().getParent());
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

输出结果是:

Member in cn.cecurio.vo
cn.cecurio.load.MyClassLoader@1540e19d
sun.misc.Launcher$AppClassLoader@232204a1
sun.misc.Launcher$ExtClassLoader@14ae5a5
null

类加载器的意义是:通过动态的路径实现类加载处理操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值