instanceOf、isInstance、isAssignableFrom 的区别
在 Java 中,对一个类的子类判断有三种方式,分别是 obj instanceof [TypeName]
、class.isInstance(obj)
、class.isAssignableFrom(class)
,他们的作用都是进行父子类型判断,然而他们的区别又在什么地方。
-
其中
instanceof
是一个 Java 原语,通过对象与类型签名进行判断,需要在编译期就进行解析成字节码。跟进 JVM 源码里,在templateTable.hpp
中发现了 instanceof 方法的定义,从其中templateTable_x86.cpp
、templateTable_arm.cpp
的instanceof
方法可得,其实现方式主要是通过汇编指令从 klass 中获取标记进行判断,逻辑比较长也就不一一分析了。对于这段冗长的汇编代码,JVM 也进行了优化,当触发 JIT 编译时,会把这段逻辑编译成机器码写入 C1 层。 -
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;
}
isAssignableFrom
也是 Class 类下的 native 方法,接收参数为 Class 类。主要逻辑与isInstance
相同,区别在于当 主体 Class 与 参数 Class 其中一个为原生类型时,则选择使用对象头判断类型是否相等。
isInstance
和 isAssignableFrom
对入参校验上也有区别,isInstance 当对象为空时将会返回 false
isAssignableFrom 则会对参数进行非空校验。
isInstance
和 isAssignableFrom
在方法标记上都有 @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
总结一下,instanceof
、isInstance
、isAssignableFrom
其实无太大区别,instanceof 和 isInstance 适用于主体是对象,并且 instanceof 需要在编译期就指定类型,灵活性不如 isInstance。而 isAssignableFrom 是针对两个类的关系校验,在泛型对比上比较适合。