我有一个C ++库,我必须在现有的Android实现中使用它。我正在使用Android NDK并通过JNI使用C ++类。
但是,我无法找到如何使用JNI在Java中子类化C ++抽象类。
我面临的问题: 我的目标是通过继承抽象C ++类为C ++中的虚方法提供Java实现。 我已经加载了本机库,我正在尝试声明本机方法。 C ++方法有关键字'virtual'。当我在加载C ++库后在Java中声明本机函数时,无法识别“virtual”。这有什么不对?
感谢任何帮助。我是JNI的新手。提前致谢。
答案 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
,意思是调用super
从iVehicle::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 ++类。