2011-06-23 6 views
5

¡Creo que logré encajar la mayor parte de la pregunta en el título de este!JNI - Conversión de jobject que representa Basic Java Objects (Boolean) a tipos básicos nativos (bool)

estoy tirando de un objeto de Java en mi nativo de C++ código:

jobject valueObject = env->CallObjectMethod(hashMapObject, hashMapGetMID, keyObject); 

Es posible que yo comprobado si el objeto de retorno es uno de los tipos nativos usando algo como:

jclass boolClass = env->FindClass("java/lang/Boolean"); 
if(env->IsInstanceOf(valueObject, boolClass) == JNI_TRUE) { } 

Entonces, ahora tengo un jobject que sé que es un booleano (observe la letra B superior) - La pregunta es, ¿cuál es la forma más eficiente (considerando que ya tengo el jobject en mi código nativo) para convertir esto en a bool. Typecasting no funciona, lo cual tiene sentido.

Aunque el ejemplo anterior es un booleano, también quiero convertir Character-> char, Short-> short, Integer-> int, Float-> float, Double-> double.

(una vez implementado que voy a publicar una respuesta a esto lo que hace Boolean.booleanValue())

+0

¿Por qué no manejar el encasillado y el desempaquetado en código Java? –

Respuesta

5

Tiene dos opciones.

La opción n. ° 1 es lo que escribió en su auto-respuesta: utilice el método público definido para cada clase para extraer el valor primitivo.

La opción n. ° 2 es más rápida pero no estrictamente legal: acceda directamente al campo interno. Para Boolean, eso sería Boolean.value. Para cada clase de cuadro primitivo tiene un fieldID para el campo "valor", y acaba de leer el campo directamente. (JNI alegremente ignora el hecho de que se declaró privado. También puede escribir en campos "finales" y hacer otras cosas que entran en la categoría "idea realmente mala")

El nombre del campo "valor" es poco probable para cambiar ya que eso rompería la serialización. Así que, oficialmente, esto no es recomendable, pero en la práctica puede salirse con la suya si es necesario.

De cualquier forma, debe almacenar en caché los valores de jmethodID/jfieldID, sin buscarlos todas las veces (las búsquedas son relativamente caras).

También podría utilizar la función IsSameObject menos costosa en lugar de IsInstanceof, porque las clases de cuadro son "finales". Eso requiere hacer una llamada GetObjectClass adicional para obtener la clase valueObject, pero solo tienes que hacer eso una vez antes de tus varias comparaciones.

Por cierto, tenga cuidado con el uso de "char". En el ejemplo anterior, está transfiriendo el resultado de CallCharMethod (un valor UTF-16 de 16 bits) a un char (un valor de 8 bits). Recuerda, ¡Char!= jchar (a menos que esté configurado de alguna manera para caracteres anchos), long! = jlong ​​(a menos que esté compilando con largos de 64 bits).

+0

¡Gran respuesta, gracias! Mucha información útil que simplemente no sé. ¿Hay algún recurso específico que recomiendas o es el enfoque probado "Blood, Sweat and Tears"? :) – Graeme

+2

Probablemente el tipo de cosas sobre las que preguntas aquí no se puede aprender de un libro. Si tiene tiempo para escribir su propia máquina virtual, seguramente aprenderá mucho; En ausencia de eso, solo escriba un montón de código y luego trate de descubrir por qué está roto. :-) – fadden

1

Esta es la solución que voy a utilizar si consigo no más de entrada. Es de esperar que no es tan difícil, pero sabiendo JNI estoy pensando que podría ser:

if  (env->IsInstanceOf(valueObject, boolClass)   == JNI_TRUE) 
    { 
     jmethodID booleanValueMID = env->GetMethodID(boolClass, "booleanValue", "()Z"); 
     bool booleanValue   = (bool) env->CallBooleanMethod(valueObject, booleanValueMID); 
     addBoolean(key, booleanValue); 
    } 
    else if(env->IsInstanceOf(valueObject, charClass)   == JNI_TRUE) 
    { 
     jmethodID characterValueMID = env->GetMethodID(charClass, "charValue", "()C"); 
     char characterValue   = (char) env->CallCharMethod(valueObject, characterValueMID); 
     addChar (key, characterValue); 
    } 
0

En general, escribo JNI para el mejor rendimiento. ¿Cómo obtener el mejor rendimiento? Usando asm, tipos primitivos y pocos métodos llaman. Sugiero que diseñar el método de tipo de retorno puede utilizar en C/C++, como jint, jlong, jboolean, jbyte y jchar etc.

La llamada de función redundante y convertir hará que la aplicación ineficiente e imposible de mantener.

+0

Voy por el código dinámico sobre el rendimiento. Los valores en tiempo de ejecución pueden ser de cualquier tipo básico, por lo que estoy tratando de encontrar la mejor forma de convertir jobject a bool/char/int, etc., sin tener que verificar su tipo y recuperarlo a través de JNI. – Graeme

+0

Haciendo dinámico y flexible en el nivel de java es mejor. Creo que si. – qrtt1

+0

¡Yo también! Pero no tengo opción sobre dónde se realizan ciertas piezas de lógica. – Graeme