zoukankan      html  css  js  c++  java
  • java中的类加载

    Class实例

    java在真正需要一个类时才由Java虚拟机JVM加载类,所谓真正需要是要通过类来构造对象或者用户自己指定要加载类。被夹在的类在java虚拟机JVM中都以一个Class实例存在。Class对象没有公开的构造器,Class对象有虚拟机JVM自动产生。也就是说,每一个类被加载,JVM虚拟机就自动为该类产生一个Class实例。

    Class的信息是在编译时期就被加入至.class文中,这是Java支持运行时类型识别(RTTI)的一种方式。一个类在JVM中只有一个Class实例,每个类的实例都会记住自己是有那个Class实例所生成。

    使用Class.forName()加载类

    Class的静态方法有两个版本,一个版本只需指定类名,而另一个版本可以指定类名称,加载类时是否运行静态区,指定类加载器:

    static Class forName(String name, boolean initialize, ClassLoader loader)

    在使用第二个版本时,可以将initialize设置为false,这样加载类时就不会运行静态区。

    下面是测试类的代码:

    package onlyfun.caterpillar;
        public class TestClass2 {
            static {
                System.out.println("[运行静态区]");
            }
        }
    package onlyfun.caterpillar;
    
    public class ForNameDemoV1 {
        public static void main(String[] args) {
            try {
                System.out.println("载入TestClass2");
                Class c = Class.forName("onlyfun.caterpillar.TestClass2"); //使用forName的第一个版本加载类
                
                System.out.println("使用TestClass2声明参考名称");
                TestClass2 test = null;
                
                System.out.println("使用TestClass2建立对象");
                test = new TestClass2();
            } catch (ClassNotFoundException e) {
                System.out.println("找不到指定的类");
            }
        }
    }

    运行结果:

    从结果看,当使用forName方法第一个版本加载类时,静态区立即运行

    下面是forName的第二个版本

    package onlyfun.caterpillar;
    
    public class ForNameDemoV2 {
        public static void main(String[] args) {
            try {
                System.out.println("载入TestClass2");
                //用forName的第二个版本加载类,initialize设置为false,不会运行静态区, 并指明了类加载器
                Class c = Class.forName("onlyfun.caterpillar.TestClass2", false, Thread.currentThread().getContextClassLoader());
                
                System.out.println("使用TestClass2声明参考变量");
                TestClass2 test = null;
                
                System.out.println("使用TestClass2建立对象");
                test = new TestClass2();
            } catch (ClassNotFoundException e) {
                System.out.println("找不到指定的类");
            }
        }
    }

    运行结果:

    从结果看,用forName方法加载TestClass2时并没有运行静态区

    类加载器

    当运行java程序的时候,运行程序会找到JRE的安装目录,然后寻找jvm.dll(默认在JRE目录下bin\client目录中), 接着JVM启动并初始化,产生Bootstrap Loader, Bootstrap Loader加载Extended Loader,并设置Bootstrap Loader为其parent,然后Extended Loader(也就是ExtClassLoader)加载System Loader(也就是AppClassLoader),并设置Extended Loader为其parent。

    Bootstrap Loader用C编写,其他两个Loader为java语言编写

    Bootstrap Loader会搜索系统参数sun.boot.class.path中指定的类,默认是JRE所在目录的classes下的.class文件,或者lib目录下的.jar文件中的类(如rt.jar)并加载。可以通过System.getProperty("sun.boot.class.path")语句显示sun.boot.class.path中指定的路径。

    Extended Loader会搜索系统参数java.ext.dirs中指定的类,默认是JRE目录下的lib/ext/classes目录下的.class文件,或者lib/ext目录下的.jar文件(如 rt.jar)中的类并加载。可以通过System.getProperty("java.ext.dirs")语句来显示java.ext.dirs中指定的路径。

    System Loader会搜索系统参数java.class.path中指定的类,也就是Classpath所指定的路径,默认是当前工作路径下的.class文件。可以使用System.getProperty("java.class.path")来显示java.class.path中指定的路径。在java运行时,也可以通过-cp来覆盖原来的Classpath设置:java -cp ./classes someClass.

    每个类加载器都会先将加载任务交给其parent,如果parent找不到,再由正自己负责,如果还找不到,就抛出NoClassDefFoundError。

    类加载器在java中都已java.lang.ClassLoader类型存在,每一个加载的类都有一个Class实例代表,而每个Class实例都会记住自己是哪一个类加载器加载的。可以有Class的getClassLoader方法取得该类的ClassLoader,耳从ClassLoader的getParent方法可以取到自己的parent。

    取得ClassLoader的实例后,可以使用loadClass方法来加载类。这个方法不会运行静态区。

    package onlyfun.caterpillar;
    
    public class ForNameDemoV3 {
        public static void main(String[] args) {
            try {
                System.out.println("使用类加载器加载类");
                ClassLoader loader = ForNameDemoV3.class.getClassLoader();//获取类加载器
                Class c = loader.loadClass("onlyfun.caterpillar.TestClass2");
            
                System.out.println("使用TestClass2声明参考名称");
                TestClass2 test = null;
            
                System.out.println("使用TestClass2建立对象");
                test = new TestClass2();
            } catch (ClassNotFoundException e) {
                System.out.println("找不到指定的类");
            }
        }
    }

    运行结果:

    使用自己的ClassLoader

    ExClassLoader和AppClassLoader都是java.net.URLClassLoader的子类,可以在使用java时用下列指令指定ExtClassLoader的所搜路径:

    java -Djava.ext.dirs = c:\workspace\Yourclass

    可以用-cp或者-classpath指定AppClassLoader的搜索路径:

    java -cp c:\workspace\Yourclass

    可以使用URLClassLoader来产生新的类加载器,它需要java.net.URL作其参数指定加载类时的搜索路径:

    URL url = new URL("file:/d:/workspace/");
    ClassLoader  urlClassLoader = new URLClassLoader(new URL[] {url});
    Class c = urlClassLoader.loadClass("Someclass");

    新建的ClassLoader会将其parent设置为AppClassLoader

    由同一个类加载器加载的类文件,会只有一份Class实例,如果同一个类文件有两个不同的ClassLoader载入,就会有两份不同的Class实例

  • 相关阅读:
    MongoDB 创建数据库
    MongoDB
    MongoDB 概念解析
    window平台安装 MongoDB(二)
    MongoDB入门学习(1)
    解决DevExpress10.2.4版本在VS2012工具箱控件不显示的问题
    Aspose.Word 输出表格后空格字符丢失的解决方法
    ArcEngine 创建空间参考设置默认域
    SPATIALITE 各版本数据库差异
    WGS84投影的WKID说明
  • 原文地址:https://www.cnblogs.com/chaoguo1234/p/2962072.html
Copyright © 2011-2022 走看看