instanceOf、isInstance、isAssignableFrom 的区别

在 Java 中,对一个类的子类判断有三种方式,分别是 obj instanceof [TypeName]class.isInstance(obj)class.isAssignableFrom(class),他们的作用都是进行父子类型判断,然而他们的区别又在什么地方。

  1. 其中 instanceof 是一个 Java 原语,通过对象与类型签名进行判断,需要在编译期就进行解析成字节码。跟进 JVM 源码里,在 templateTable.hpp 中发现了 instanceof 方法的定义,从其中 templateTable_x86.cpptemplateTable_arm.cppinstanceof 方法可得,其实现方式主要是通过汇编指令从 klass 中获取标记进行判断,逻辑比较长也就不一一分析了。对于这段冗长的汇编代码,JVM 也进行了优化,当触发 JIT 编译时,会把这段逻辑编译成机器码写入 C1 层。

  2. isInstance 是 Class 类下的 native 方法,接收参数为对象。分析了在 jni.cpp 中的大体流程,程序先通过 class 获取到 Klass,调用 object 内 klass 的 is_subtype_of 方法,传入方才获取的 Klass,判断二者地址是否相同,是则判定为同一类型,否则再调用 search_secondary_supers,判断父级类型是否存在与传入的 Klass 相匹配。

JNI_QUICK_ENTRY(jboolean, jni_IsInstanceOf(JNIEnv *env, jobject obj, jclass clazz))
  JNIWrapper("IsInstanceOf");

  HOTSPOT_JNI_ISINSTANCEOF_ENTRY(env, obj, clazz);

  jboolean ret = JNI_TRUE;
  if (obj != NULL) {
    ret = JNI_FALSE;
    Klass* k = java_lang_Class::as_Klass(
      JNIHandles::resolve_non_null(clazz));
    if (k != NULL) {
      ret = JNIHandles::resolve_non_null(obj)->is_a(k) ? JNI_TRUE : JNI_FALSE;
    }
  }

  HOTSPOT_JNI_ISINSTANCEOF_RETURN(ret);
  return ret;
JNI_END

// hotspot/share/oops/oop.inline.hpp

bool oopDesc::is_a(Klass* k) const {
  return klass()->is_subtype_of(k);
}
// hotspot/share/oops/klass.hpp

// subtype check: true if is_subclass_of, or if k is interface and receiver implements it
bool is_subtype_of(Klass* k) const {
  juint    off = k->super_check_offset();
  Klass* sup = *(Klass**)( (address)this + off );
  const juint secondary_offset = in_bytes(secondary_super_cache_offset());
  if (sup == k) {
    return true;
  } else if (off != secondary_offset) {
    return false;
  } else {
    return search_secondary_supers(k);
  }
}

bool Klass::search_secondary_supers(Klass* k) const {
  // Put some extra logic here out-of-line, before the search proper.
  // This cuts down the size of the inline method.

  // This is necessary, since I am never in my own secondary_super list.
  if (this == k)
    return true;
  // Scan the array-of-objects for a match
  int cnt = secondary_supers()->length();
  for (int i = 0; i < cnt; i++) {
    if (secondary_supers()->at(i) == k) {
      ((Klass*)this)->set_secondary_super_cache(k);
      return true;
    }
  }
  return false;
}
  1. isAssignableFrom 也是 Class 类下的 native 方法,接收参数为 Class 类。主要逻辑与 isInstance 相同,区别在于当 主体 Class 与 参数 Class 其中一个为原生类型时,则选择使用对象头判断类型是否相等。

isInstanceisAssignableFrom 对入参校验上也有区别,isInstance 当对象为空时将会返回 false isAssignableFrom 则会对参数进行非空校验。

isInstanceisAssignableFrom 在方法标记上都有 @HotSpotIntrinsicCandidate,会被 JVM 使用更高效的字节码替换,节省了 JNI 调用的开销。

JNI_QUICK_ENTRY(jboolean, jni_IsAssignableFrom(JNIEnv *env, jclass sub, jclass super))
  JNIWrapper("IsSubclassOf");

  HOTSPOT_JNI_ISASSIGNABLEFROM_ENTRY(env, sub, super);

  oop sub_mirror   = JNIHandles::resolve_non_null(sub);
  oop super_mirror = JNIHandles::resolve_non_null(super);
  if (java_lang_Class::is_primitive(sub_mirror) ||
      java_lang_Class::is_primitive(super_mirror)) {
    jboolean ret = oopDesc::equals(sub_mirror, super_mirror);

    HOTSPOT_JNI_ISASSIGNABLEFROM_RETURN(ret);
    return ret;
  }
  Klass* sub_klass   = java_lang_Class::as_Klass(sub_mirror);
  Klass* super_klass = java_lang_Class::as_Klass(super_mirror);
  assert(sub_klass != NULL && super_klass != NULL, "invalid arguments to jni_IsAssignableFrom");
  jboolean ret = sub_klass->is_subtype_of(super_klass) ?
                   JNI_TRUE : JNI_FALSE;

  HOTSPOT_JNI_ISASSIGNABLEFROM_RETURN(ret);
  return ret;
JNI_END

总结一下,instanceofisInstanceisAssignableFrom 其实无太大区别,instanceof 和 isInstance 适用于主体是对象,并且 instanceof 需要在编译期就指定类型,灵活性不如 isInstance。而 isAssignableFrom 是针对两个类的关系校验,在泛型对比上比较适合。

参考: https://stackoverflow.com/questions/496928/what-is-the-difference-between-instanceof-and-class-isassignablefrom