2

我使用常规 std::map 将 jobject 映射到 c++ 对象。这种方法的问题在于它可能对其他类型的引用失败,例如全局引用实际上是不同于常规局部引用的指针,即使它们引用同一个对象。比较两个引用是否引用同一个对象的正确方法是:

env->IsSameObject(jobj1, jobj2);

所以,我的问题是:将 jobject 映射到 c++ 对象的正确方法是什么?将 jobject 包装到重载 operator== 并调用 IsSameObject 的某个 c++ 类中的明显回复不是我正在寻找的回复。我想知道是否有办法做到这一点,而无需在每次比较操作中在 JVM 和本机 c/c++ 之间来回切换。

编辑:全局引用是一个 jni 全局引用,与 c++ 引用无关。

EDIT2:我想澄清一下这段代码有什么问题:

std::map<jobject, void *> jobjs;
jobject obj1, obj2;
... some code that sets these obj1 and obj2 to some Java objects.

jobjs[obj1] = new CppPeer;
CppPeer * = jobjs[obj1]; //OK...
if(objs.find(obj2) == objs.end()){
   assert(obj2 != obj1);
   //Here's the problem: here a new c++ CppPeer
   //created for obj2, but the problem is that 
   //even if obj1 != ob2 it doesn't mean that
   //they actually reference different java objects
   //On the next line error might happen
   jobjs[obj2] = new CppPeer; //maybe not OK here...
}

IsSameObject 的另一个问题是它使事情变得非常讨厌和混乱。不仅现在我需要保留一个指向 JVM 的指针,而且每当我需要比较作业时,我都需要附加线程等以获取指向 JNIEnv 的指针,以便能够检查作业

EDIT3:请注意,根据 android 文档,如果它们相等,您甚至不能假设两个引用引用同一个对象。我不知道这怎么可能,但Android的JNI提示页面中有一部分:

这样做的一个后果是,您不能假设对象引用在本机代码中是恒定的或唯一的。表示一个对象的 32 位值可能与一个方法的调用不同,并且有可能两个不同的对象在连续调用时可能具有相同的 32 位值。不要使用 jobject 值作为键

4

1 回答 1

1

免责声明:它闻起来。

在 Android 上,指针 和jint大小相同。考虑向您的 Java 类添加一个 int 字段来存储指向本机 conterpart 的指针。在 JNI 方法中,将其类型转换回指针。

为了稍微安全一点,对数据类型匹配做一个静态断言:

{char a[sizeof(void*) == sizeof(jint) ? 1 : -1]};

如果它是在一个不是它的系统上编译的,你会得到一个编译错误。

为了稍微减少气味,使用静态/全局map从 int 到您的对象,使用 ID 生成器,而不是对象指针,在 Java 对象中存储相对唯一的(在进程生命周期内)对象 ID。

于 2012-10-24T01:57:19.310 回答