2013-08-07 14 views
5

Ich habe eine C++ - Bibliothek, die ich in einer bestehenden Android-Implementierung verwenden muss. Ich benutze Android NDK und verwende die C++ Klassen über JNI.Unterklasse eine C++ - abstrakte Klasse in Java mit JNI

Ich bin jedoch nicht in der Lage zu finden, wie eine C++ - abstrakte Klasse in Java unter Verwendung von JNI abgeleitet wird.

Probleme, denen ich gegenüberstehe: Mein Ziel ist es, Java-Implementierung für die virtuellen Methoden in C++ durch Unterklasse der abstrakten C++ - Klasse bereitzustellen. Ich habe die native Bibliothek geladen und ich versuche, die nativen Methoden zu deklarieren. Die C++ - Methoden haben das Schlüsselwort 'virtual'. Wenn ich die nativen Funktionen in Java nach dem Laden der C++ - Bibliothek deklariere, wird 'virtual' nicht erkannt. Was ist hier falsch?

Jede Hilfe wird geschätzt. Ich bin ein Neuling für JNI. Danke im Voraus.

+1

Starten Sie [hier] (http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/intro.html#wp725). Sie werden feststellen, dass der JNI-Kleber Java nicht an C++ - Klassen bindet. Dafür braucht man etwas, das um JNI herum gebaut ist.[Jace] (http://code.google.com/p/jace/wiki/Overview) ist nützlich, geht aber nicht so weit, wie du es beschrieben hast. Meine Wette ist, dass Sie nichts finden werden, das Sie vermeidet, manuell eine konkrete C++ - Klasse zu erstellen und diese zu umhüllen. –

+0

@TomBlodget: Danke! Schlagen Sie zum Erstellen von Wrappern ein Tool wie SWIG vor oder gibt es eine andere Möglichkeit? – vvid

+0

Schauen Sie sich auch [BridJ] (http://bridj.googlecode.com) an. –

Antwort

5

Wir betrachten wir haben eine C++ Klasse:

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 
}; 

Wir wollen eine Klasse Bot in Java erstellen, die Klasse iVehicle im Sinne erstreckt, der den C++ Code aus iVehicle::GetSize() und vom C bis super aufrufen ruft ++ Sichtweise können wir die Instanzen Bot als iVehicle* Variablen verwenden. Das ist schwierig, da C++ keine integrierte Funktionalität für Reflektionen bietet.

Hier ist eine mögliche Lösung.

Um C++ Klasse in Java verwenden wir einen Java-Wrapper, dh generieren müssen:

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(); 
} 

Die Verwendung in Java ist einfach:

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

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

Allerdings gibt es eine C++ Teil ist Dieser 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(); 
} 

Der ähnliche Code ist für GetSize().

Dann erstellen Sie eine Instanz von Java's Bot Sie müssen CreateNativeObject() aufrufen und den zurückgegebenen Wert dem Feld NativeObjectHolder zuweisen.

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

Also, das ist das Schema. Damit dies funktioniert, müssen Sie den Löschcode hinzufügen und C++ - Klassen analysieren, um den gesamten Klebecode zu generieren.

Hinzugefügt:

Im Fall, in dem iVehicle eigentlich abstrakt ist, werden Sie eine nicht-abstrakte Wrapper generieren müssen, dass Sie in der Lage sind zu instanziiert:

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

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

Und instanziiert iVehicle_Wrapper in CreateNativeObject(). Vuala! Sie haben eine abstrakte C++ - Klasse in Java geerbt.

+0

Vielen Dank für die ausführliche Antwort. Aber, wenn ich eine Java-Implementierung für die abstrakten Methoden der C++ - Klasse bereitstellen möchte und diese Java-Unterklasse wieder in C++ verwenden möchte? – vvid

+0

Die Verwendung von Java-Unterklassen in C++ ist eine Fortsetzung dieser Geschichte. Sie müssen einen Wrapper "iVehicle_Wrapper" generieren, der eine ID des Java-Objekts/Methode enthält und JNI verwendet, um sie aufzurufen. –

+0

Ich schlage vor, Sie untersuchen * Peer-Klassen *. Sie werden eine Java-Proxy-Klasse für "IVehicle" - eine abstrakte Klasse auf der Java-Seite der Dinge, die die C++ - Methoden spiegelt. Auf C++ - Seite möchten Sie eine konkrete Implementierung von 'iVehicle', die alle abstrakten virtuellen Funktionen implementiert und diese mit JNI an den Java-Proxy weiterleitet. – marko

Verwandte Themen