JNI:如何检查两个 jclass 实例实际上引用相同的 Java class?

JNI: how to check that two jclass instances actually refer to the same Java class?

我在 Android 6 (ART) 上的 JNI 本机代码有点问题。我有一个方法可以接收 jclass 实例并存储此 class 引用以供将来使用。为此,我需要创建对此 jclass 的引用,以便它以后不会变得无效:

std::set<jclass> storedClasses;

void storeClass(jclass cls)
{
   TraceLog << "Original jclass:" << cls;
   jclass clsRef = (jclass)env.jniEnv()->NewGlobalRef(cls);
   TraceLog << "New jclass global reference:" << cls;

   storedClasses.insert(clsRef);
}

需要注意的是,我只需要将每个 class 存储一次 (因此为容器选择 std::set - 它保证所有项是唯一的),但 NewGlobalRef 实际上每次都会创建一个新的、不同的 jclass 值。这是有道理的,但我相信直到最近才出现这种情况。我不能再使用这个值本身(它只是一个指针)来确保唯一性。

如何检查两个不同的 jclass 实例是否指向相同或不同的 Java classes?将 jclass 转换回 jobject 并对其调用 java.lang.Object.hashcode 会产生所需的结果吗?

更新:奇怪,我可以成功调用hashcode(),但总是returns -1.
更新二: this 也不行,怎么试都是java.lang.Class

我认为这里的问题是您正在存储 clsRef,这是您转换为 jclassjobject。它不是真正的 jclass,而是一个不同的对象,它是对原始 class.

的引用

您需要在商店中存储一些东西作为该全局引用的键。那东西必须唯一标识class.

你的店是一套的,我觉得你需要,比如哈希 table.

如果 FindClass() returns 相同参数每次都具有相同的值,那么可以使用,但我目前无法测试。我怀疑你需要做一个 GetName(),但是,同样,现在不能发短信。

NewGlobalRef 创建一个新引用,而不是新对象或 class 对象的实例。如果你调用它两次,你会得到两个不同的值,这两个值都不会与你最初得到的本地引用相同。 IsSameObject 调用会告诉您它们都引用同一事物,并且是确定两个引用是否指向同一对象的唯一可靠方法。

您不能简单地使用引用创建集合,因为引用不是唯一的。如果您唯一的要求是避免添加重复对象,则可以在添加新成员时执行 O(n) 系列的 IsSameObject 调用。谨慎使用散列码——对象的散列码不会改变,因此如果散列码不匹配,您有两个不同的对象,但两个不同的对象可以具有相同的散列码。

另一种方法是使用 JNI 调用将 class 对象存储在 Java 语言数据结构中,例如 HashSet;这会增加 JNI 调用的额外开销,但如果您要存储大量对象,改进的数据结构可能会有所帮助。

(琐事:在 ICS 之前,Dalvik 会简单地 return 一个指向引用对象的指针,因此您实际上可以简单地创建一个本机集。这种方法使复杂的堆管理变得更加困难,因此引入了 ICS 版本"indirect" 引用,它们是扩充的 table 索引而不是指针。)