类文件解析006-解析接口

本文来介绍一下解析接口的部分,这部分的代码比较简单,算是为了给之后解析变量内容的减压.

为了内容的连贯性,先来看一下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;
}

注释写的比较详细,流程简单,这里就不再展开了.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值