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 JNICALL
Java_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) {
/* slashes present in clname, use name b4 translation for exception */
(*env)->GetStringUTFRegion(env, classname, 0, unicode_len, clname);
JNU_ThrowClassNotFoundException(env, clname);
goto done;
}

if (!VerifyClassname(clname, JNI_TRUE)) { /* expects slashed name */
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虚拟机