Java中的ClassLoader核心知识点有哪些

发布时间:2021-10-25 13:55:03 作者:iii
来源:亿速云 阅读:177

这篇文章主要介绍“Java中的ClassLoader核心知识点有哪些”,在日常操作中,相信很多人在Java中的ClassLoader核心知识点有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中的ClassLoader核心知识点有哪些”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

JDK 和 JRE 的作用

JAVAHOME、PATH、CLASSPATH

类加载器的种类

在JVM中有三类ClassLoader构成:

Java中的ClassLoader核心知识点有哪些

(1) Bootstrap ClassLoader

Bootstrap ClassLoader 最顶层的类加载器,主要加载核心类库 %JRE_HOME%\lib 下的  rt.jar、resources.jar、charsets.jar 和 class文件等。

//执行 System.out.println(System.getProperty("sun.boot.class.path")); //输出结果 D:\Program Files\Java\jdk1.8.0_241\jre\lib\resources.jar; D:\Program Files\Java\jdk1.8.0_241\jre\lib\rt.jar; D:\Program Files\Java\jdk1.8.0_241\jre\lib\sunrsasign.jar; D:\Program Files\Java\jdk1.8.0_241\jre\lib\jsse.jar; D:\Program Files\Java\jdk1.8.0_241\jre\lib\jce.jar; D:\Program Files\Java\jdk1.8.0_241\jre\lib\charsets.jar; D:\Program Files\Java\jdk1.8.0_241\jre\lib\jfr.jar; D:\Program Files\Java\jdk1.8.0_241\jre\classes

(2) Extention ClassLoader

Extention ClassLoader 扩展的类加载器,主要加载目录 %JRE_HOME%\lib\ext 目录下的jar包和class文件。

//执行 System.out.println(System.getProperty("java.ext.dirs")); //输出 D:\Program Files\Java\jdk1.8.0_241\jre\lib\ext;C:\Windows\Sun\Java\lib\ext

(3) Appclass Loader

Appclass Loader也称为SystemAppClass 加载当前应用的classpath的所有类。

类加载器的执行顺序

除启动类加载器(Bootstrap  ClassLoader)外,扩展类加载器和应用类加载器都是通过类sun.misc.Launcher进行初始化,而Launcher类则由启动类加载器进行加载。Launcher相关代码如下:

public Launcher() {     Launcher.ExtClassLoader var1;     try {         //初始化扩展类加载器,构造函数没有入参,无法获取启动类加载器         var1 = Launcher.ExtClassLoader.getExtClassLoader();     } catch (IOException var10) {         throw new InternalError("Could not create extension class loader", var10);     }      try {         //初始化应用类加载器,入参为扩展类加载器         this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);     } catch (IOException var9) {         throw new InternalError("Could not create application class loader", var9);     }      // 设置上下文类加载器     Thread.currentThread().setContextClassLoader(this.loader);         //... }

加载顺序:Bootstrap CLassloder > Extention ClassLoader > AppClassLoader

父加载器概念

AppClassLoader 和 ExtClassLoader 都继承了  URLClassLoader。每个类加载器都有一个父加载器(注意:父类和父加载器是两个不同的概念),可通过 getParent() 获取父类加载器。

System.out.println("ClassLoader is:"+cl.toString()); System.out.println("ClassLoader\'s parent is:"+cl.getParent().toString());System.out.println("ClassLoader\'s grand father is:"+cl.getParent().getParent().toString());

双亲委派

双亲委派模型:当一个类加载器接收到类加载请求时,会先请求其父类加载器加载,依次递归,当父类加载器无法找到该类时(根据类的全限定名称),子类加载器才会尝试去加载。

Java中的ClassLoader核心知识点有哪些

Java中的ClassLoader核心知识点有哪些

时序图

为什么使用双亲委派模型?

双亲委派模型是为了保证Java核心库的类型安全。所有Java应用都至少需要引用java.lang.Object类,在运行时这个类需要被加载到Java虚拟机中。如果该加载过程由自定义类加载器来完成,可能就会存在多个版本的java.lang.Object类,而且这些类之间是不兼容的。

通过双亲委派模型,对于Java核心库的类的加载工作由启动类加载器来统一完成,保证了Java应用所使用的都是同一个版本的Java核心库的类,是互相兼容的。

自定义类加载器

不管是Bootstrap  ClassLoader还是ExtClassLoader等,这些类加载器都只是加载指定的目录下的jar包或者资源。如果我们需要动态加载比如从指定目录中加载一个class文件,这时候通过自定义类加载器可以实现。

自定义类加载器只需要继承java.lang.ClassLoader类,然后重写findClass(String  name)方法即可,在方法中指明如何获取类的字节码流。如果要破坏双亲委派规范的话,还需重写loadClass方法(双亲委派的具体逻辑实现)。但不建议这么做。

public class ClassLoaderTest extends ClassLoader {      private String classPath;      public ClassLoaderTest(String classPath) {         this.classPath = classPath;     }      /**      * 编写findClass方法的逻辑      *      * @param name      * @return      * @throws ClassNotFoundException      */     @Override     protected Class<?> findClass(String name) throws ClassNotFoundException {         // 获取类的class文件字节数组         byte[] classData = getClassData(name);         if (classData == null) {             throw new ClassNotFoundException();         } else {             // 生成class对象             return defineClass(name, classData, 0, classData.length);         }     }      /**      * 编写获取class文件并转换为字节码流的逻辑      *      * @param className      * @return      */     private byte[] getClassData(String className) {         // 读取类文件的字节         String path = classNameToPath(className);         try {             InputStream is = new FileInputStream(path);             ByteArrayOutputStream stream = new ByteArrayOutputStream();             byte[] buffer = new byte[2048];             int num = 0;             // 读取类文件的字节码             while ((num = is.read(buffer)) != -1) {                 stream.write(buffer, 0, num);             }             return stream.toByteArray();         } catch (IOException e) {             e.printStackTrace();         }         return null;     }      /**      * 类文件的完全路径      *      * @param className      * @return      */     private String classNameToPath(String className) {         return classPath + File.separatorChar                 + className.replace('.', File.separatorChar) + ".class";     }      public static void main(String[] args) {         String classPath = "/Users/zzs/my/article/projects/java-stream/src/main/java/";         ClassLoaderTest loader = new ClassLoaderTest(classPath);          try {             //加载指定的class文件             Class<?> object1 = loader.loadClass("com.secbro2.classload.SubClass");             System.out.println(object1.newInstance().toString());         } catch (Exception e) {             e.printStackTrace();         }     } }

到此,关于“Java中的ClassLoader核心知识点有哪些”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

推荐阅读:
  1. HBase核心知识点有哪些
  2. JAVA的核心知识点

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java classloader

上一篇:如何掌握Rust包管理器Cargo

下一篇:Python爬虫经常会被封的原因是什么

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》