• 深入理解java:1.1. 类加载器


    从java的动态性到类加载机制

     

    我们知道,Java是一种动态语言。

    那么怎样理解这个“动态”呢?

    或者说一门语言具备了什么特性,才能称之为动态语言呢?

    对于java,我是这样理解的。

    我们都知道JVM(java虚拟机)执行的不是本地机器码指令,

    而是执行一种称之为字节码的指令(存在于class文件中)。

    这就要求虚拟机在真正执行字节码之前,先把相关的class文件加载到内存中。

    虚拟机不是一次性加载所有需要的class文件,因为它在执行的时候根本不会知道以后会用到哪些class文件。

    它是每用到一个类,就会在运行时“动态地”加载和这个类相关的class文件。

    这就是java被称之为动态性语言的根本原因。

    除了动态加载类之外,还会动态的初始化类,对类进行动态链接。

    在JVM中负责对类进行加载的正是本文要介绍的类加载器(ClassLoader),所以,类加载器是JVM不可或缺的重要组件。

     

    java中的类加载器及类加载器工作原理

     

    java中(指的是javase)有三种类加载器。

    每个类加载器在创建的时候已经指定他们对应的目录, 也就是说每个类加载器去哪里加载类是确定的,我认为在ClassLoader类中应该会有getTargetPath()之类的方法, 得到他们对应的路径,找了找jdk的文档,发现是没有的。

    以下是这三种类加载器和他们对应的路径:

     * AppClassLoader  --   加载classpath指定的路径中的类

     * ExtClassLoader   --   加载jre/lib/ext目录下或者java.ext.dirs系统属性定义的目录下的类

     * BootStrap           --   加载JRE/lib/rt.jar中的类

    那么类加载器是如何工作的呢?

    可以参看jdk中ClassLoader类的源码。这个类的实现使用了模板方法模式,首先是loadClass方法来加载类,loadClass方法又调用了findClass方法,该方法读取并返回类文件的数据,findClass方法返回后,loadClass方法继续调用defineClass方法,将返回的数据加工成虚拟机运行时可识别的类型信息。

    所以,我们如果开发自己的类加载器,只需要继承jdk中的ClassLoader类,并覆盖findClass方法就可以了,剩下的而工作,父类会完成。

    1. class MyClassLoader extends ClassLoader {  
    2.     @Override  
    3.     public Class<?> loadClass(String name) throws ClassNotFoundException {  
    4.         String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";  
    5.         InputStream in = getClass().getResourceAsStream(fileName);  
    6.         if (in == null) {  
    7.             return super.loadClass(name);  
    8.         }  
    9.         byte[] b = null;  
    10.         try {  
    11.             b = new byte[in.available()];  
    12.             in.read(b);  
    13.             in.close();  
    14.         } catch (IOException e) {  
    15.             e.printStackTrace();  
    16.         }  
    17.         return defineClass(name, b, 0, b.length);  
    18.     }  
    19. }  

    其他java平台有的根据自己的需求,实现了自己特定的类加载器,

    例如javaee平台中的tomcat服务器,Android平台中的dalvik虚拟机也定义了自己的类加载器。

    虚拟机加载类有两种方式,一种方式就是上面提到的ClassLoader.loadClass()方法,

    另一种是使用反射API,Class.forName()方法,其实Class.forName()方法内部也是使用的ClassLoader。

    指定参数ClassLoader的话就用指定的;否则,返回的是调用者的类加载器。

    Class类中forName方法的实现如下:

    [java] 
     
    1. public static Class<?> forName(String name, boolean initialize,  
    2.                    ClassLoader loader)  
    3.         throws ClassNotFoundException  
    4.     {  
    5.     if (loader == null) {  
    6.         SecurityManager sm = System.getSecurityManager();  
    7.         if (sm != null) {  
    8.         ClassLoader ccl = ClassLoader.getCallerClassLoader();  
    9.         if (ccl != null) {  
    10.             sm.checkPermission(  
    11.             SecurityConstants.GET_CLASSLOADER_PERMISSION);  
    12.         }  
    13.         }  
    14.     }  
    15.     return forName0(name, initialize, loader);  
    16.     }  
    17.   
    18.     /** Called after security checks have been made. */  
    19.     private static native Class forName0(String name, boolean initialize,  
    20.                         ClassLoader loader)  
    21.     throws ClassNotFoundException;  
  • 相关阅读:
    CF321B Solution
    CF722D Solution
    CF729E Solution
    CF1447E Solution
    CF962F Solution
    DropDownList绑定数据
    连接数据库
    jqm随记的东西
    正则表达式过滤超链接内容(.net)
    linq lambda操作list的例子
  • 原文地址:https://www.cnblogs.com/my376908915/p/6752390.html
Copyright © 2020-2023  润新知