使用JNI在Java中对C ++抽象类进行子类化

时间:2013-08-07 18:08:10

标签: android-ndk java-native-interface

我有一个C ++库,我必须在现有的Android实现中使用它。我正在使用Android NDK并通过JNI使用C ++类。

但是,我无法找到如何使用JNI在Java中子类化C ++抽象类。

我面临的问题: 我的目标是通过继承抽象C ++类为C ++中的虚方法提供Java实现。 我已经加载了本机库,我正在尝试声明本机方法。 C ++方法有关键字'virtual'。当我在加载C ++库后在Java中声明本机函数时,无法识别“virtual”。这有什么不对?

感谢任何帮助。我是JNI的新手。提前致谢。

1 个答案:

答案 0 :(得分:5)

让我们考虑一下我们有一个C ++类:

class iVehicle
{
public:
   virtual void Run() {}; // not-pure virtual here for simplicity of a wrapper, but could be pure (see the end of the post)
   virtual int  GetSize() const; // we want to reuse it in Java
};

我们希望在Java中创建一个类Bot,它扩展了类iVehicle,意思是调用superiVehicle::GetSize()调用C ++代码,并从C ++中调用从观点来看,我们可以将Bot的实例用作iVehicle*个变量。这很难,因为C ++没有为反射提供良好的内置功能。

以下是一种可能的解决方案。

要在Java中使用C ++类,我们需要生成一个Java包装器,即:

class iVehicle
{
   public void Run() { Native_Run(); }
   public int  GetSize() { return Native_GetSize(); }

   private native void Native_Run();
   private native int  Native_GetSize();

   // typecasted to pointer in C++
   private int NativeObjectHolder;

   // create C++ object
   native static private int CreateNativeObject();
}

Java中的用法很简单:

class Bot extends iVehicle
{
   public int GetSize()
   {
      if ( condition ) return 0;

      // call C++ code
      return super.GetSize();
   }
}

但是,此代码中有一个C ++部分:

static jfieldID gNativeObjectHolderFieldID;

JNIEXPORT void JNICALL Java_com_test_iVehicle_Run( JNIEnv* env, jobject thiz )
{
   int Value = env->GetIntField(thiz, gNativeObjectHolderFieldID);
   iVehicle* Obj = (iVehicle*)Obj;

   // todo: add checks here, for NULL and for dynamic casting

   Obj->Run();
}

类似的代码适用于GetSize()

然后创建Java Bot的实例,您必须调用CreateNativeObject()并将返回的值分配给NativeObjectHolder字段。

JNIEXPORT int JNICALL Java_com_test_iVehicle_CreateNativeObject( JNIEnv* env, jobject thiz )
{
   iVehicle* Obj = new iVehicle;
   return (int)Obj;    
}

所以,这就是计划。为了完成这项工作,您需要添加销毁代码并解析C ++类以生成所有这些粘合代码。

<强>加了:

如果iVehicle实际上是抽象的,您将必须生成一个可以实例化的非抽象包装器:

class iVehicle
{
   virtual void Run() = 0;
}

class iVehicle_Wrapper: public iVehicle
{
   virtual void Run() { ERROR("Abstract method called"); };
}

iVehicle_Wrapper中实例化CreateNativeObject()。 Vuala!您已经在Java中继承了一个抽象的C ++类。