本文来介绍一下解析接口的部分,这部分的代码比较简单,算是为了给之后解析变量内容的减压.
为了内容的连贯性,先来看一下class文件的格式:
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count; --> 在调用ClassFileParser::parse_constant_pool时ClassFileStream的指针就指向这里
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
对接口涉及到的字段说明如下:
-
interfaces_count
接口计数器,interfaces_count的值表示当前类或接口的直接父接口数量。
-
interfaces[]
接口表,interfaces[]数组中的每个成员的值必须是一个对constant_pool表中项目的一个有效索引值,它的长度为interfaces_count。每个成员interfaces[i] 必须为CONSTANT_Class_info类型常量,其中0 ≤ i < interfaces_count。在interfaces[]数组中,成员所表示的接口顺序和对应的源代码中给定的接口顺序(从左至右)一样,即interfaces[0]对应的是源代码中最左边的接口。
解析
本文所涉及的代码如下:
// Interfaces 7. 读取接口信息,接口类型包括本地接口和父类传递接口
u2 itfs_len = cfs->get_u2_fast();
objArrayHandle local_interfaces;
if (itfs_len == 0) {
// 7.1 如果接口不存在,则返回一个空数组
local_interfaces = objArrayHandle(THREAD, Universe::the_empty_system_obj_array());
} else {
// 7.2 解析接口
local_interfaces = parse_interfaces(cp, itfs_len, class_loader, protection_domain, _class_name, CHECK_(nullHandle));
}
此时,需要注意的是,如果是没有接口的话,则会复用之前实例化的空数组(这个数组是在Universe::genesis(TRAPS) 方法中创建的,在类加载流程003, 类加载流程004 中有介绍 ).
接下来,我们来看一下ClassFileParser::parse_interfaces,其代码如下:
objArrayHandle ClassFileParser::parse_interfaces(constantPoolHandle cp,
int length,
Handle class_loader,
Handle protection_domain,
symbolHandle class_name,
TRAPS) {
ClassFileStream* cfs = stream();
assert(length > 0, "only called for length>0");
// 1. 在内存中分配长度为length 的 数组
objArrayHandle nullHandle;
objArrayOop interface_oop = oopFactory::new_system_objArray(length, CHECK_(nullHandle));
objArrayHandle interfaces (THREAD, interface_oop);
int index;
// 2. 依次进行解析
for (index = 0; index < length; index++) {
// 2.1 进行验证,1<= interface_index < interfaces_count,并且常量池中interface_index的必须是CONSTANT_Class_info类型常量
u2 interface_index = cfs->get_u2(CHECK_(nullHandle));
KlassHandle interf;
check_property(
valid_cp_range(interface_index, cp->length()) &&
is_klass_reference(cp, interface_index),
"Interface name has bad constant pool index %u in class file %s",
interface_index, CHECK_(nullHandle));
// 2.2 如果interface_index所对应的类,已经加载过,则直接使用即可
if (cp->tag_at(interface_index).is_klass()) {
interf = KlassHandle(THREAD, cp->resolved_klass_at(interface_index));
} else {
// 2.3 如果没有加载过,则进行加载
symbolHandle unresolved_klass (THREAD, cp->klass_name_at(interface_index));
// Don't need to check legal name because it's checked when parsing constant pool.
// But need to make sure it's not an array type.
// 2.3.1 不需要检查其名字格式是否正确,因为其在解析常量池时已经检查过了.但是需要检查其不是数组类型
guarantee_property(unresolved_klass->byte_at(0) != JVM_SIGNATURE_ARRAY,
"Bad interface name in class file %s", CHECK_(nullHandle));
// Call resolve_super so classcircularity is checked
// 2.3.2 进行解析
klassOop k = SystemDictionary::resolve_super_or_fail(class_name,
unresolved_klass, class_loader, protection_domain,
false, CHECK_(nullHandle));
interf = KlassHandle(THREAD, k);
if (LinkWellKnownClasses) // my super type is well known to me
cp->klass_at_put(interface_index, interf()); // eagerly resolve
}
// 2.4 如果不是接口,则抛出异常
if (!Klass::cast(interf())->is_interface()) {
THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(), "Implementing class", nullHandle);
}
// 2.5 保存到数组中
interfaces->obj_at_put(index, interf());
}
// 3.1 如果不需要验证或者接口的长度为1,则不需要进行重复接口的交易
if (!_need_verify || length <= 1) {
return interfaces;
}
// Check if there's any duplicates in interfaces 检查是否有重复的接口
ResourceMark rm(THREAD);
NameSigHash** interface_names = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, NameSigHash*, HASH_ROW_SIZE);
initialize_hashtable(interface_names);
bool dup = false;
{
debug_only(No_Safepoint_Verifier nsv;)
for (index = 0; index < length; index++) {
klassOop k = (klassOop)interfaces->obj_at(index);
symbolOop name = instanceKlass::cast(k)->name();
// If no duplicates, add (name, NULL) in hashtable interface_names.
if (!put_after_lookup(name, NULL, interface_names)) {
dup = true;
break;
}
}
}
if (dup) {
// 3.2 如果有重复的接口,则抛出异常
classfile_parse_error("Duplicate interface name in class file %s",
CHECK_(nullHandle));
}
return interfaces;
}
注释写的比较详细,流程简单,这里就不再展开了.