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
,这是您转换为 jclass
的 jobject
。它不是真正的 jclass
,而是一个不同的对象,它是对原始 class.
的引用
您需要在商店中存储一些东西作为该全局引用的键。那东西必须唯一标识class.
你的店是一套的,我觉得你需要,比如哈希 table.
如果 FindClass()
returns 相同参数每次都具有相同的值,那么可以使用,但我目前无法测试。我怀疑你需要做一个 GetName()
,但是,同样,现在不能发短信。
NewGlobalRef
创建一个新引用,而不是新对象或 class 对象的实例。如果你调用它两次,你会得到两个不同的值,这两个值都不会与你最初得到的本地引用相同。 IsSameObject
调用会告诉您它们都引用同一事物,并且是确定两个引用是否指向同一对象的唯一可靠方法。
您不能简单地使用引用创建集合,因为引用不是唯一的。如果您唯一的要求是避免添加重复对象,则可以在添加新成员时执行 O(n) 系列的 IsSameObject
调用。谨慎使用散列码——对象的散列码不会改变,因此如果散列码不匹配,您有两个不同的对象,但两个不同的对象可以具有相同的散列码。
另一种方法是使用 JNI 调用将 class 对象存储在 Java 语言数据结构中,例如 HashSet;这会增加 JNI 调用的额外开销,但如果您要存储大量对象,改进的数据结构可能会有所帮助。
(琐事:在 ICS 之前,Dalvik 会简单地 return 一个指向引用对象的指针,因此您实际上可以简单地创建一个本机集。这种方法使复杂的堆管理变得更加困难,因此引入了 ICS 版本"indirect" 引用,它们是扩充的 table 索引而不是指针。)
我在 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
,这是您转换为 jclass
的 jobject
。它不是真正的 jclass
,而是一个不同的对象,它是对原始 class.
您需要在商店中存储一些东西作为该全局引用的键。那东西必须唯一标识class.
你的店是一套的,我觉得你需要,比如哈希 table.
如果 FindClass()
returns 相同参数每次都具有相同的值,那么可以使用,但我目前无法测试。我怀疑你需要做一个 GetName()
,但是,同样,现在不能发短信。
NewGlobalRef
创建一个新引用,而不是新对象或 class 对象的实例。如果你调用它两次,你会得到两个不同的值,这两个值都不会与你最初得到的本地引用相同。 IsSameObject
调用会告诉您它们都引用同一事物,并且是确定两个引用是否指向同一对象的唯一可靠方法。
您不能简单地使用引用创建集合,因为引用不是唯一的。如果您唯一的要求是避免添加重复对象,则可以在添加新成员时执行 O(n) 系列的 IsSameObject
调用。谨慎使用散列码——对象的散列码不会改变,因此如果散列码不匹配,您有两个不同的对象,但两个不同的对象可以具有相同的散列码。
另一种方法是使用 JNI 调用将 class 对象存储在 Java 语言数据结构中,例如 HashSet;这会增加 JNI 调用的额外开销,但如果您要存储大量对象,改进的数据结构可能会有所帮助。
(琐事:在 ICS 之前,Dalvik 会简单地 return 一个指向引用对象的指针,因此您实际上可以简单地创建一个本机集。这种方法使复杂的堆管理变得更加困难,因此引入了 ICS 版本"indirect" 引用,它们是扩充的 table 索引而不是指针。)