使用 JNI 子类化 Java 中的 C++ 抽象类 [英] Subclass a C++ abstract class in Java using JNI

查看:27
本文介绍了使用 JNI 子类化 Java 中的 C++ 抽象类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a C++ library that I have to use in an existing Android implementation. I'm using Android NDK and using the C++ classes via JNI.

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

However, I am not able to find how to subclass a C++ abstract class in Java using JNI.

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

Problems I face: My aim is to provide Java implementation for the virtual methods in C++ by subclassing the abstract C++ class. I have loaded the native library and I'm trying to declare the native methods. The C++ methods have keyword 'virtual'. When I declare the native functions in Java after loading the C++ library, 'virtual' is not recognized. What is wrong here?

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

Any help is appreciated. I'm a newbie to JNI. Thanks in advance.

推荐答案

假设我们有一个 C++ 类:

Let's consider we have a C++ class:

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,即调用 super 调用来自 iVehicle::GetSize() 并且从 C++ 的角度来看,我们可以将 Bot 的实例用作 iVehicle* 变量.这很难,因为 C++ 没有为反射提供好的内置功能.

We want to create a class Bot in Java that extends class iVehicle in the sense that calls to super invoke the C++ code from iVehicle::GetSize() and, from the C++ point of view, we can use the instances of Bot as iVehicle* variables. That's tough since C++ provides no good built-in functionality for reflection.

这是一种可能的解决方案.

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

To use C++ class in Java we need to generate a Java wrapper, i.e:

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中的用法很简单:

The usage in Java is simple:

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

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

但是,这段代码有一个 C++ 部分:

However, there is a C++ part to this code:

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 字段.

Then creating an instance of Java's Bot you have to call CreateNativeObject() and assign the returned value to the NativeObjectHolder field.

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

所以,这就是方案.要完成这项工作,您需要添加销毁代码并解析 C++ 类以生成所有这些胶水代码.

So, this is the scheme. To make this work you will need to add the destruction code and to parse C++ classes to generate all this glue code.

添加:

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

In case where iVehicle is actually abstract you will have to generate a non-abstract wrapper that you are able to instantiate:

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

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

并在CreateNativeObject()中实例化iVehicle_Wrapper.瓦拉!您在 Java 中继承了一个抽象 C++ 类.

And instantiate iVehicle_Wrapper in CreateNativeObject(). Vuala! You have inherited an abstract C++ class in Java.

这篇关于使用 JNI 子类化 Java 中的 C++ 抽象类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆