2011-06-07 23 views
5

Tengo un par de funciones JNI que tienen que funcionar en el mismo objeto C++. Me gustaría guardar ese objeto en el objeto java a través del cual se invocan las funciones JNI, pero parece que Java no tiene manera de almacenar punteros para que las funciones puedan acceder más tarde.Devolver el objeto C++ a Java

bien soy consciente de que estoy haciendo un trabajo terrible explicar a mí mismo por lo que aquí es un ejemplo:

void clear_numbers(JNIEnv *env, jobject me) { 
    me.myCppVector.clear(); 
} 

void set_number(JNIEnv *env, jobject me, jint index, jint num) { 
    me.myCppVector[index]=num; 
} 

jint get_number(JNIEnv *env, jobject me, jint index) { 
    returnme.myCppVector[index]; 
} 

Mi problema es la creación de un jobject.myCppVector por lo que voy a ser capaz de utilizarlo de diferentes llamadas de función.

espero que alguien entiende mis divagaciones

+1

tal vez convertir el puntero a un entero, y luego almacenar el número entero en un campo del objeto Java – ignis

+0

No es eso considera que no es seguro? Además, ¿sizeof (jint) es igual a sizeof (void *) en todas las plataformas? – Afiefh

+0

No conozco ninguna razón por la cual no sea seguro. Sin embargo, los punteros tienen diferentes tamaños en diferentes plataformas, mientras que los tipos primitivos Java no, y por supuesto esto significa que necesitaría mapear punteros a primitivas de diferentes tipos en el código Java - int para 32 bit, long para 64 bit, etc. http://java.sun.com/docs/books/jls/second_edition/html/typesValues.doc.html#85587 – ignis

Respuesta

4

Creo que la forma normal de hacer las cosas es el uso de un largo en Java para almacenar el puntero, de esa manera el código Java funciona en ambos sistemas de 32 y 64 bits. Obviamente, necesita compilar un C++ .so/.dll diferente para cada plataforma.

Así que un simple envoltorio Java para una clase de C++ con un método será algo como:

class JavaClass 
{ 
    private long native_ptr = 0; 
    private native long createNativeInstance(params); 
    private native String nativeMethod(params); 
    private native void destroyNativeInstance(long p_native_ptr); 
    public JavaClass(params) 
    { 
     this.native_ptr = createNativeInstance(params); 
    } 
    public String javaMethod(params) 
    { 
     nativeMethod(this.native_ptr, params); 
    } 
    public void finalize() 
    { 
     destroyNativeInstance(this.native_ptr); 
    } 
} 

Y su código C++ envoltorio se ve algo como esto. (He llamado la clase de C++ CppClass)

JNIEXPORT jlong JNICALL Java_JavaClass_createNativeInstance 
    (JNIEnv* p_jenv 
    , jobject p_jthis 
    , params) 
{ 
    // Convert params from Java types to C++ types if required 
    return (jlong) new CppClass(converted_params); 
} 

JNIEXPORT void JNICALL Java_JavaClass_destroyNativeInstance 
    (JNIEnv* p_jenv 
    , jobject p_jthis 
    , jlong  p_native_ptr) 
{ 
    if(p_native_ptr) 
     delete (CppClass*)p_native_ptr; 
} 

JNIEXPORT jstring JNICALL Java_JavaClass_nativeMethod 
    (JNIEnv* p_jenv 
    , jobject p_jthis 
    , jlong  p_native_ptr 
    , params 
    ) 
{ 
    // Convert params from Java types to C++ types if required 
    std::string cpp_result = ((CppClass*)p_native_ptr)->cppMethod(converted_params); 
    jstring java_result = p_jenv->NewStringUTF(cppResult.c_str()); 
    return java_result; 
    // NOTE: std::string destructor will free cpp_result memory 
} 
Cuestiones relacionadas