zoukankan      html  css  js  c++  java
  • 类加载的表现形式

    java中的类是动态加载的,我们先看一下我们常用的类加载方式,先有一个感性的认识,才能进一步

    深入讨论,类加载无非就是下面三种方式。

    class A{}

    class B{}

    class C{}

    public class Loader{

        public static void main(String[] args) throws Exception{

           Class aa=A.class; 

           Class bb=Class.forName("B");

           Class cc=ClassLoader.getSystemClassLoader().loadClass("C");

        }

    }

    我们先看.class字面量方式,很多人可能不知道这种方式,因为这种用法不是一般java语法。

    通过javap我们可以发现,这种方式的大致等价于定义了一个静态成员变量

        static Class class$0;(后面的编号是增长的)

    你可以试图再定义一个  static Class class$0,应该会收到一个编译错误(重复定义)。

    Class aa=A.class;

    就相当于

        if(class$0==null){

     try{ 

               Class.forName("A");

     }

     cacth(ClassNotFoundException e){

        throw new NoClassDefFoundError(e);

     }

        }

        Class aa=class$0;

    可以很清楚的看到,这种类的字面量定义其实不是加载类的方式,而是被编译器处理了,实质

    上是使用了Class.forName方法,但是使用这种方式有一个很大的好处就是不用处理异常,因为

    编译器处理的时候如果找不到类会抛出一个NoClassDefFoundError。也许你觉得需要处理

    ClassNotFoundException这种异常,事实上99%的情况下我们可以把这种异常认为是一个错误。

    所以大部分情况我们使用这种方式会更简洁。

    最常用的方式就是Class.forName方式了,这也是一个通用的上层调用。这个方法有两个重载,

    可能很多人都忽略了第二个方法。

    public static Class forName(String name) throws ClassNotFoundException

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

    第二个方法后面多了两个参数,第二个参数表示是否初始化,第三个参数为指定的类加载器。

    在上面的例子中:

    Class bb=Class.forName("B");等价于

    Class bb=Class.forName("B",true,Loader.class.getClassLoader());

    这里要详细说一下这个类的初始化这个参数,如果这个参数为false的话,

    类中的static成员不会被初始化,static语句块也不会被执行。

    也就是类虽然被加载了,但是没有被初始化,不过在第一次使用时仍然会初始化。

    所以我们有时候会看到Class.forName("XXX").newInstance()这样的语句,为什么这里要创建一个

    不用的实例呢?不过是为了保证类被初始化(兼容以前的系统)。

    其实第二个方法是比较难用的,需要指定类加载器,如果不指定而且又没有安装安全管理器的化,

    是无法加载类的,只要看一下具体的实现就明白了。

    最本质的方式当然是直接使用ClassLoader加载了,所有的类最终都是通过ClassLoader加载的,

    Class cc=ClassLoader.getSystemClassLoader().loadClass("C");

    这里通过使用系统类加载器来加载某个类,很直接的方式,但是很遗憾的是通过这种方式加载类,

    类是没有被初始化的(也就是初始化被延迟到真正使用的时候).不过我们也可以借鉴上面的经验,加载

    后实例化一个对象Class cc=ClassLoader.getSystemClassLoader().loadClass("C").newInstance()。

    这里使用了系统类加载器,也是最常用的类加载器,从classpath中寻找要加载的类。

    java中默认有三种类加载器:引导类加载器,扩展类加载器,系统类加载器。

    java中的类加载有着规范的层次结构,如果我们要了解类加载的过程,需要明确知道哪个类被谁

    加载,某个类加载器加载了哪些类等等,就需要深入理解ClassLoader的本质。

    以上只是类加载的表面的东西,我们还将讨论深层次的东西。

     

  • 相关阅读:
    zookeeper报错java.net.ConnectException: Connection refused: no further information
    dubbo 使用zookeeper 出现 Dubbo客户端调用报错NullPointerException
    docker下载镜像received unexpected Http status:500 Internal Server Error
    Spring Security 无法登陆,报错:There is no PasswordEncoder mapped for the id “null”
    js 解决中文乱码的问题
    使用Elasticsearch 出现的拒绝连接
    com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class cn.edu.
    yii2判断数据库字段is null
    MySQL之终端(Terminal)管理数据库、数据表、数据的基本操作
    yii2.0-rules验证规则应用实例
  • 原文地址:https://www.cnblogs.com/borter/p/9434108.html
Copyright © 2011-2022 走看看