zoukankan      html  css  js  c++  java
  • 触发类的装载

    首先来介绍一下类加载的时机,下面5种情况会导致类初始化,所以必然在此之前对类进行加载,如下:(参考:深入理解Java虚拟机)

    • 当虚拟机启动时加载主类,之前对于主类的加载时详细介绍过;
    • 使用java.lang.reflect包的方法对类进行反射调用;
    • new一个类的对象,调用类的静态成员(除了由final修饰的常量外)和静态方法,无论是在解析执行还是编译执行情况下,都会在处理new、getstatic、putstatic 或invokestatic字节码指令时需要对类进行初始化;
    • 当初始化一个类,如果其父类没有被初始化,则先初始化它父类,后续在介绍初始化方法InstanceKlass::initialize_impl()时会看到这个逻辑;
    • 当使用JDK 1. 7 的动态语言支持时,如果一个java. lang. invoke. MethodHandle 实例最后的解析结果REF_ getStatic、REF_ putStatic、REF_ invokeStatic 的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。

    关于主类的加载在之前已经介绍过,通过调用ClassLoader类的loadClass()方法来完成,还可以通过调用java.lang.Class.forName()方法通过反射的方法完成类加载,但是loadClass()只是将Class文件加载到HotSpot中,而forName()方法会完成方法的加载、链接和初始化。

    forName()方法的实现如下:

    @CallerSensitive
    public static Class<?> forName(String className)
                    throws ClassNotFoundException {
            Class<?> caller = Reflection.getCallerClass();
            // 第2个参数的值为true,表示要对类进行初始化 
            return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }
    

    调用的forName0()是一个本地静态方法,如下:

    private static native Class<?> forName0(String name, boolean initialize,
                                                ClassLoader loader,
                                                Class<?> caller)
            throws ClassNotFoundException;
    

    HotSpot提供了这个方法的本地接口实现,如下:

    源代码位置:openjdk/jdk/src/share/native/java/lang/Class.c

    JNIEXPORT jclass JNICALL
    Java_java_lang_Class_forName0(JNIEnv *env, jclass this, jstring classname,
                                  jboolean initialize, jobject loader)
    {
        char *clname;
        jclass cls = 0;
     
        cls = JVM_FindClassFromClassLoader(env, clname, initialize,
                                           loader, JNI_FALSE);
     
        return cls;
    }
    

    调用JVM_FindClassFromClassLoader()函数,实现如下:

    JVM_ENTRY(jclass, JVM_FindClassFromClassLoader(JNIEnv* env, const char* name,
                                                   jboolean init, jobject loader,
                                                   jboolean throwError))
      // ...
      TempNewSymbol h_name = SymbolTable::new_symbol(name, CHECK_NULL);
      Handle h_loader(THREAD, JNIHandles::resolve(loader));
      jclass result = find_class_from_class_loader(env, h_name, init, h_loader,
                                                   Handle(), throwError, THREAD);
      return result;
    JVM_END
    

    调用的find_class_from_class_loader()函数的实现如下:

    jclass find_class_from_class_loader(JNIEnv* env, Symbol* name, jboolean init, Handle loader, Handle protection_domain, jboolean throwError, TRAPS) {
      // Security Note:
      //   The Java level wrapper will perform the necessary security check allowing
      //   us to pass the NULL as the initiating class loader.
      Klass* klass = SystemDictionary::resolve_or_fail(name, loader, protection_domain, throwError != 0, CHECK_NULL);
    
      KlassHandle klass_handle(THREAD, klass);
      // Check if we should initialize the class
      if (init && klass_handle->oop_is_instance()) { // init的值为true
        klass_handle->initialize(CHECK_NULL); // 对类进行初始化操作
      }
      return (jclass) JNIHandles::make_local(env, klass_handle->java_mirror());
    }

    调用SystemDictionary::resolve_or_fail()在之前介绍过,方法会遵循双亲委派机制来加载类,通常是创建或从Dictionary中查询已经加载的instanceKlass实例,不涉及到对类的连接、初始化等。通过forName()调用此方法时,会执行类的初始化操作,我们在后面专门会介绍类的初始化,这里暂不介绍。 

    相关文章的链接如下:

    1、在Ubuntu 16.04上编译OpenJDK8的源代码 

    2、调试HotSpot源代码

    3、HotSpot项目结构 

    4、HotSpot的启动过程 

    5、HotSpot二分模型(1)

    6、HotSpot的类模型(2)  

    7、HotSpot的类模型(3) 

    8、HotSpot的类模型(4)

    9、HotSpot的对象模型(5)  

    10、HotSpot的对象模型(6) 

    11、操作句柄Handle(7)

    12、句柄Handle的释放(8)

    13、类加载器 

    14、类的双亲委派机制 

    15、核心类的预装载

    16、Java主类的装载  

    作者持续维护的个人博客classloading.com

    关注公众号,有HotSpot源码剖析系列文章!

      

  • 相关阅读:
    await Task.Delay(delay)
    C# MemberwiseClone浅复制
    wpf如何在ItemTemplate绑定viewModel对象
    resful接口请求token认证方式
    Convert.ToInt32与int区别强制转换区别
    亿量级App Push系统(4)--渠道推送
    亿量级App Push系统(3)--推送服务
    亿量级App Push系列(2)--模板管理
    亿量级 App Push系列(1)--设备管理
    MySQL如何查看大事务
  • 原文地址:https://www.cnblogs.com/mazhimazhi/p/13354961.html
Copyright © 2011-2022 走看看