欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

Class.forName底层原理

时间:2023-06-20
Class Class.forName

public static Class<?> forName(String className) throws ClassNotFoundException { Class<?> caller = Reflection.getCallerClass(); // caller : class field.ClassForNameDemo return forName0(className, true, ClassLoader.getClassLoader(caller), caller); }

forName0

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

Class.c

JNIEXPORT jclass JNICALLJava_java_lang_Class_forName0(JNIEnv *env, jclass this, jstring classname, jboolean initialize, jobject loader, jclass caller){ char *clname; jclass cls = 0; char buf[128]; jsize len; jsize unicode_len; if (classname == NULL) { JNU_ThrowNullPointerException(env, 0); return 0; } len = (*env)->GetStringUTFLength(env, classname); unicode_len = (*env)->GetStringLength(env, classname); if (len >= (jsize)sizeof(buf)) { clname = malloc(len + 1); if (clname == NULL) { JNU_ThrowOutOfMemoryError(env, NULL); return NULL; } } else { clname = buf; } (*env)->GetStringUTFRegion(env, classname, 0, unicode_len, clname); if (VerifyFixClassname(clname) == JNI_TRUE) { (*env)->GetStringUTFRegion(env, classname, 0, unicode_len, clname); JNU_ThrowClassNotFoundException(env, clname); goto done; } if (!VerifyClassname(clname, JNI_TRUE)) { JNU_ThrowClassNotFoundException(env, clname); goto done; } cls = JVM_FindClassFromCaller(env, clname, initialize, loader, caller); // jvm.cpp:896 done: if (clname != buf) { free(clname); } return cls;}

JVM_FindClassFromCaller

// Find a class with this name in this loader, using the caller's protection domain.JVM_ENTRY(jclass, JVM_FindClassFromCaller(JNIEnv* env, const char* name, jboolean init, jobject loader, jclass caller)) JVMWrapper2("JVM_FindClassFromCaller %s throws ClassNotFoundException", name); // Java libraries should ensure that name is never null... if (name == NULL || (int)strlen(name) > Symbol::max_length()) { // It's impossible to create this class; the name cannot fit // into the constant pool. THROW_MSG_0(vmSymbols::java_lang_ClassNotFoundException(), name); // java_lang_ClassNotFoundException } TempNewSymbol h_name = SymbolTable::new_symbol(name, CHECK_NULL); oop loader_oop = JNIHandles::resolve(loader); // oop result = (handle == NULL ? (oop)NULL : *(oop*)handle); oop from_class = JNIHandles::resolve(caller); oop protection_domain = NULL; // If loader is null, shouldn't call ClassLoader.checkPackageAccess; otherwise get // NPE、Put it in another way, the bootstrap class loader has all permission and // thus no checkPackageAccess equivalence in the VM class loader. // The caller is also passed as NULL by the java code if there is no security // manager to avoid the performance cost of getting the calling class. if (from_class != NULL && loader_oop != NULL) { protection_domain = java_lang_Class::as_Klass(from_class)->protection_domain(); } Handle h_loader(THREAD, loader_oop); Handle h_prot(THREAD, protection_domain); jclass result = find_class_from_class_loader(env, h_name, init, h_loader, h_prot, false, THREAD); // 4094 if (TraceClassResolution && result != NULL) { trace_class_resolution(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result))); } 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、 The VM is responsible for // the checkPackageAccess relative to the initiating class loader via the // protection_domain、The protection_domain is passed as NULL by the java code // if there is no security manager in 3-arg Class.forName(). Klass* klass = SystemDictionary::resolve_or_fail(name, loader, protection_domain, throwError != 0, CHECK_NULL); // todo create instanceClass KlassHandle klass_handle(THREAD, klass); // Check if we should initialize the class if (init && klass_handle->oop_is_instance()) { klass_handle->initialize(CHECK_NULL); // 调用下面方法 } // instanceMirrorClass return (jclass) JNIHandles::make_local(env, klass_handle->java_mirror());}

InstanceKlass::initialize(TRAPS)

void InstanceKlass::initialize(TRAPS) { if (this->should_be_initialized()) { initialize_impl(CHECK); // Note: at this point the class may be initialized // OR it may be in the state of being initialized // in case of recursive initialization! } else { assert(is_initialized(), "sanity check"); }}

InstanceKlass::initialize_impl

void InstanceKlass::initialize_impl(TRAPS) { HandleMark hm(THREAD); // Make sure klass is linked (verified) before initialization // A class could already be verified, since it has been reflected upon. link_class(CHECK); // link_class_impl(CHECK); DTRACE_CLASSINIT_PROBE(required, -1); bool wait = false; // refer to the JVM book page 47 for description of steps // Step 1 { Handle h_init_lock(THREAD, init_lock()); ObjectLocker ol(h_init_lock, THREAD, h_init_lock() != NULL); Thread *self = THREAD; // it's passed the current thread // Step 2 // If we were to use wait() instead of waitInterruptibly() then // we might end up throwing IE from link/symbol resolution sites // that aren't expected to throw、 This would wreak havoc、 See 6320309. while(is_being_initialized() && !is_reentrant_initialization(self)) { wait = true; ol.waitUninterruptibly(CHECK); } // Step 3 if (is_being_initialized() && is_reentrant_initialization(self)) { DTRACE_CLASSINIT_PROBE_WAIT(recursive, -1, wait); return; } // Step 4 if (is_initialized()) { DTRACE_CLASSINIT_PROBE_WAIT(concurrent, -1, wait); return; } // Step 5 if (is_in_error_state()) { DTRACE_CLASSINIT_PROBE_WAIT(erroneous, -1, wait); ResourceMark rm(THREAD); const char* desc = "Could not initialize class "; const char* className = external_name(); size_t msglen = strlen(desc) + strlen(className) + 1; char* message = NEW_RESOURCE_ARRAY(char, msglen); if (NULL == message) { // Out of memory: can't create detailed error message THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), className); } else { jio_snprintf(message, msglen, "%s%s", desc, className); THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), message); } } // Step 6 set_init_state(being_initialized); set_init_thread(self); } // Step 7 // Next, if C is a class rather than an interface, initialize it's super class and super // interfaces. if (!is_interface()) { Klass* super_klass = super(); if (super_klass != NULL && super_klass->should_be_initialized()) { super_klass->initialize(THREAD); } // If C implements any interface that declares a non-static, concrete method, // the initialization of C triggers initialization of its super interfaces. // only need to recurse if has_nonstatic_concrete_methods which includes declaring and // having a superinterface that declares, non-static, concrete methods if (!HAS_PENDING_EXCEPTION && has_nonstatic_concrete_methods()) { initialize_super_interfaces(THREAD); } // If any exceptions, complete abruptly, throwing the same exception as above. if (HAS_PENDING_EXCEPTION) { Handle e(THREAD, PENDING_EXCEPTION); CLEAR_PENDING_EXCEPTION; { EXCEPTION_MARK; // Locks object, set state, and notify all waiting threads set_initialization_state_and_notify(initialization_error, THREAD); CLEAR_PENDING_EXCEPTION; } DTRACE_CLASSINIT_PROBE_WAIT(super__failed, -1, wait); THROW_OOP(e()); } } // Look for aot compiled methods for this klass, including class initializer. AOTLoader::load_for_klass(this, THREAD); // Step 8 { assert(THREAD->is_Java_thread(), "non-JavaThread in initialize_impl"); JavaThread* jt = (JavaThread*)THREAD; DTRACE_CLASSINIT_PROBE_WAIT(clinit, -1, wait); // Timer includes any side effects of class initialization (resolution, // etc), but not recursive entry into call_class_initializer(). PerfClassTraceTime timer(ClassLoader::perf_class_init_time(), ClassLoader::perf_class_init_selftime(), ClassLoader::perf_classes_inited(), jt->get_thread_stat()->perf_recursion_counts_addr(), jt->get_thread_stat()->perf_timers_addr(), PerfClassTraceTime::CLASS_CLINIT); call_class_initializer(THREAD); } // Step 9 if (!HAS_PENDING_EXCEPTION) { set_initialization_state_and_notify(fully_initialized, CHECK); { debug_only(vtable().verify(tty, true);) } } else { // Step 10 and 11 Handle e(THREAD, PENDING_EXCEPTION); CLEAR_PENDING_EXCEPTION; // JVMTI has already reported the pending exception // JVMTI internal flag reset is needed in order to report ExceptionInInitializerError JvmtiExport::clear_detected_exception((JavaThread*)THREAD); { EXCEPTION_MARK; set_initialization_state_and_notify(initialization_error, THREAD); CLEAR_PENDING_EXCEPTION; // ignore any exception thrown, class initialization error is thrown below // JVMTI has already reported the pending exception // JVMTI internal flag reset is needed in order to report ExceptionInInitializerError JvmtiExport::clear_detected_exception((JavaThread*)THREAD); } DTRACE_CLASSINIT_PROBE_WAIT(error, -1, wait); if (e->is_a(SystemDictionary::Error_klass())) { THROW_OOP(e()); } else { JavaCallArguments args(e); THROW_ARG(vmSymbols::java_lang_ExceptionInInitializerError(), vmSymbols::throwable_void_signature(), &args); } } DTRACE_CLASSINIT_PROBE_WAIT(end, -1, wait);}

InstanceKlass::link_class

void InstanceKlass::link_class(TRAPS) { assert(is_loaded(), "must be loaded"); if (!is_linked()) { link_class_impl(CHECK); }}

其他

如果当前类没有被装载,那么最终会调用ClassFileParser::parseClassFile()函数加载类,然后调用InstanceKlass::initialize()函数进行连接这个函数最终会调用InstanceKlass::link_class_impl()函数

类的连接步骤

连接父类和实现的接口,子类在连接之前要保证父类和接口已经连接进行字节码验证重写类连接方法初始化vtable和itable以上步骤执行完成后,将表示类状态的_init_state属性标记为已连接状态

参考书籍

深入剖析Java虚拟机

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。