讓我們考慮,我們有一個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
,在調用到super
從iVehicle::GetSize()
調用C++代碼,從C的意義延伸iVehicle
類++觀點來看,我們可以使用Bot
作爲iVehicle*
變量的實例。這很難,因爲C++沒有提供用於反射的良好內置功能。
以下是一種可能的解決方案。
要使用C++類在Java中,我們需要生成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"); };
}
而且在CreateNativeObject()
實例iVehicle_Wrapper
。 Vuala!您已經繼承了Java中的抽象C++類。
開始[這裏](http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/intro.html#wp725)。你會發現JNI glue並沒有將Java與C++類聯繫起來。爲此,你需要一些圍繞JNI構建的東西。[Jace](http://code.google.com/p/jace/wiki/Overview)很有用,但不會像你所描述的那樣。我敢打賭,你不會找到任何避免你手動創建一個具體的C++類幷包裝的東西。 –
@TomBlodget:謝謝!爲了創建包裝,你建議使用像SWIG這樣的工具還是有其他方法可以做到這一點? – vvid
請看[BridJ](http://bridj.googlecode.com)。 –