2013-08-07 65 views
5

我有一個C++庫,我必須在現有的Android實現中使用它。我正在使用Android NDK並通過JNI使用C++類。使用JNI在Java中爲C++抽象類子類化

但是,我無法找到如何使用JNI在Java中對C++抽象類進行子類化。

我面臨的問題: 我的目標是通過繼承抽象C++類來爲C++中的虛擬方法提供Java實現。 我已經加載了本地庫,我試圖聲明本地方法。 C++方法有關鍵字'虛擬'。當我在加載C++庫後在Java中聲明本地函數時,「虛擬」無法識別。這裏有什麼問題?

任何幫助表示讚賞。我是JNI的新手。提前致謝。

+1

開始[這裏](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++類幷包裝的東西。 –

+0

@TomBlodget:謝謝!爲了創建包裝,你建議使用像SWIG這樣的工具還是有其他方法可以做到這一點? – vvid

+0

請看[BridJ](http://bridj.googlecode.com)。 –

回答

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,在調用到superiVehicle::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++類。

+0

謝謝你的詳細回覆。但是,如果我想爲C++類的抽象方法提供Java實現並希望再次在C++中使用此Java子類,該怎麼辦? – vvid

+0

在C++中使用Java子類是本文的續篇。您需要生成一個封裝「iVehicle_Wrapper」,它將保存Java對象/方法的ID並使用JNI來調用它。 –

+0

我建議你調查*同儕班*。你將爲'IVehicle'的Java代理類 - 這是一個鏡像C++方法的Java方面的抽象類。在C++端,你需要一個具體實現'iVehicle'來實現所有的抽象虛函數,並將它們用JNI轉發給Java代理。 – marko