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

vpl*_*lus 5 java-native-interface android-ndk

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

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

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

任何帮助表示赞赏.我是JNI的新手.提前致谢.

Ser*_* K. 6

让我们考虑一下我们有一个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
};
Run Code Online (Sandbox Code Playgroud)

我们希望Bot在Java中创建一个类,它iVehiclesuper调用C++代码的意义上扩展了类iVehicle::GetSize(),从C++的角度来看,我们可以使用Botas 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();
}
Run Code Online (Sandbox Code Playgroud)

Java中的用法很简单:

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

      // call C++ code
      return super.GetSize();
   }
}
Run Code Online (Sandbox Code Playgroud)

但是,这段代码有一个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();
}
Run Code Online (Sandbox Code Playgroud)

类似的代码是为了GetSize().

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

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

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

添加:

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

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

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

并实例iVehicle_WrapperCreateNativeObject().Vuala!您已经在Java中继承了一个抽象的C++类.