JNI:将jobject映射到本机c ++对象

时间:2012-10-23 23:40:29

标签: android c++ android-ndk java-native-interface

我使用常规的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的指针,而且每当我需要比较jobjects时,我需要附加线程等来获取指向JNIEnv的指针以便能够检查jobject

EDIT3:请注意,根据Android文档,您甚至不能假设两个引用在相同的情况下引用相同的对象。我不知道它是如何可能的,但Android的JNI提示页面中有一部分:

  

这样做的一个结果是您不能假设对象引用   在本机代码中是常量或唯一的。表示的32位值   一个对象可能与一个方法的调用不同   接下来,两个不同的对象可能具有相同的功能   连续呼叫的32位值。不要将jobject值用作键

1 个答案:

答案 0 :(得分:1)

免责声明:它闻起来。

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

为了更安全一些,在数据类型匹配上执行静态断言:

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

如果它是在不是的系统上编译的,那么你会收到编译错误。

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