Java 类加载器 ClassLoader

三大类加载器

package com.classloader;

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

/**
 * 类加载器:
 *编写的 .java文件需要先编译成 .class文件,当程序运行时,
 *如果需要用到某个类,JVM 通过 类加载器ClassLoader 把对应的class文件加载到内存中,然后再执行代码
 *
 * 三大类加载器
 * Bootstrap ClassLoader	启动类加载器、引导类加载器
 * Extension ClassLoader 	扩展类类加载器
 * App ClassLoader			系统类加载器,应用类加载器
 */
public class Demo {
    public static void main(String[] args) {
        /**
         * 1.Bootstrap ClassLoader 启动类加载器
         *  下例子中输出null,原因: 因为Bootstrap ClassLoader是虚拟机JRE的一部分,不是Java类库中的某个类
         *   既然不是一个类,就不能使用引用指向它
         *  主要用于加载JDK核心类库,C++语言实现的,加载时的搜索路径是由 sun.boot.class.path 所指定的
         *  比如:%JRE_HOME%\jre\lib下的rt.jar、resources.jar、charsets.jar等。
         *
         * 在运行/调试配置中添加VM选项进行修改
         *  -Xbootclasspath:路径     指定的路径会完全取代jdk核心的搜索路径    坚决不要用
         *  -Xbootclasspath/a:路径    指定的路径会在jdk核心类后搜索            可用
         *  -Xbootclasspath/p:路径    指定的路径会在jdk核心类前搜索            可用,不建议使用
         *
         */
        //输出null,表示Bootstrap ClassLoader
        System.out.println(String.class.getClassLoader());
        //获取扫描路径
        String paths = System.getProperty("sun.boot.class.path");
        String[] arr = paths.split(";"); //window是";",unix是":"
        for (String path : arr) {
            System.out.println(path);
        }

        /**
         * 2.Extension ClassLoader  扩展类类加载器
         * 配置路径:在运行/调试配置中添加VM选项
         * 扩展类加载器,加载 -Djava.ext.dirs 选项指定的目录
         * 比如: %JRE%\jre\lib\ext目录下的jar包和class文件
         *
         * 注意: 如果配置自定义路径,或覆盖默认路径
         */
//        System.out.println(DNSNameService.class.getClassLoader());
//        String paths = System.getProperty("java.ext.dirs");
//        String[] arr = paths.split(";");
//        for (String path : arr) {
//            System.out.println(path);
//        }

        /**
         *3. AppClassLoader 系统类加载器,又叫: 应用类加载器
         *  它的搜索路径由java.class.path(CLASSPATH)来指定
         *  主要用来加载程序中的类文件,及引用的第三放库
         *
         *  AppClassLoader的父亲是Extension ClassLoader
         * 父亲和父类不是同一个概念,父亲的儿子有getParent方法,而子类没有
         */
//        System.out.println(Demo.class.getClassLoader());
//        System.out.println(Demo.class.getClassLoader().getParent());
//        //System.getProperty用于扫描路径
//        String paths = System.getProperty("java.class.path");
//        String[] arr = paths.split(";");
//        for (String path : arr) {
//            System.out.println(path);
//        }

        /**
         * sun.misc.Launcher$AppClassLoader@18b4aac2
         * sun.misc.Launcher$ExtClassLoader@74a14482
         * 从显示的结果来看是Launcher$AppClassLoader类和Launcher$ExtClassLoader
         * 这两个对象在哪初始化的呢?
         * 搜索Launcher类发现getClassLoader方法也是在Launcher类中,是java应用程序的入口类
         * 其实AppClassLoader和ExtClassLoader是Launcher的内部类
         */
    }
}

双亲委派模式

package com.classloader;

public class Demo2 {
    /**
     *双亲委派模式
     * 简称: 坑爹模式
     *  即:如果一个类加载器要加载某个类,它并不会自己先去加载,而是让父加载器/父亲,则进一步向上委托,一次递归
     *  最终将到达顶层的启动类加载器(Bootstrap ClassLoader)
     *  如果父加载器可用完成加载任务,就成功返回
     *  如果父加载器无法完成此加载任务,子加载器才会自己去加载
     */

    /**
     * 类的加载是在main方法之前执行的,查看Launcher.class 使用ctrl+n进行所有查询
     * 所有类的加载都是要走 174处 loadClass(String var1, boolean var2)这个方法
     * 在195处 return super.loadClass(var1, var2);下断点,不只是程序的类进行加载还有系统类要进行加载
     * 所以调试时放过系统类加载 也就是恢复程序 F9,一直放过到出现var1="com.classloader.Demo2"
     * 然后对loadClass(var1, var2)方法进行追踪(强制步入Alt+Shift+F7),从Launcher.class类跳转到ClassLoader类中
     *
     * 好处:
     *  1.避免类的重复加载
     *  2.保证java核心api不会被随意替换
     * @param args
     */

    public static void main(String[] args) {
        System.out.println(Demo2.class.getClassLoader());
    }
}

urlclassloader可以指定一串路径,然后在路径下面寻找要加载的类

package com.classloader;

/**
 * URLClassLoader
 * 是ExtClassLoader和AppClassLoader的父类
 *它可以从指定的 jar 文件和目录中加载类和资源
 *
 * 使用:
 * 1.创建对象
 * 2.执行loadClass方法
 *
 * 构造方法:
 * URLClassLoader(URL[] urls, ClassLoader parent):使用指定的父加载器创建对象,从指定的urls路径来查询、并加载类。
 * URLClassLoader(URL[] urls):使用默认的父加载器(AppClassLoader)创建一个ClassLoader对象,从指定的urls路径来查询、并加载类。
 *
 * 需求:解析Excel,一般我们用poi,目前模板不确定,而且客户不希望每次改一种模板就重启应用。
 * 解决:把解析代码抽出来,打成一个jar包,每次上传模板的时候,就选用指定的jar包运行,因为需要动态加载jar包,所以需要用到类加载器
 *      最终利用反射对应的方法,获取结果。
 *
 */

import java.io.File;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

/**
 * 创建一个项目起名字为untitled7并创建一个com.test软件包
 * 创建一个ParseExcel类内容为
 * public class ParseExcel {
 *     public void parse() {
 *         System.out.println("执行解析Excel方法..........");
 *     }
 * }
 * 并将untitled7项目进行打包为 untitled7-1.0-SNAPSHOT.jar
 * 路径为 D:\\Java_Code\\untitled7\\target\\untitled7-1.0-SNAPSHOT.jar
 * 也可以将 untitled7-1.0-SNAPSHOT.jar 重新放在一个新的目录下
 *
 */

public class Demo3 {
    public static void main(String[] args) throws Exception {
        File file = new File("D:\\Java_Code\\classloader\\untitled7-1.0-SNAPSHOT.jar");
        URL[] urls = new URL[]{file.toURI().toURL()};
        //这时候myClassLoader跟AppClassLoader是父子关系
        URLClassLoader myClassLoader = new URLClassLoader(urls);
        Class<?> aClass = myClassLoader.loadClass("com.test.ParseExcel");
        //利用反射创建对象,并执行方法
        Object obj =  aClass.newInstance();
        Method parse = aClass.getMethod("parse");
        parse.invoke(obj,null);

    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值