I think I managed to fit most of the question in to the title on this one!
I'm pulling开发者_开发百科 back an Object from Java in my native C++ code:
jobject valueObject = env->CallObjectMethod(hashMapObject, hashMapGetMID, keyObject);
It's possible for me to check wether the return object is one of the native types using something like:
jclass boolClass = env->FindClass("java/lang/Boolean");
if(env->IsInstanceOf(valueObject, boolClass) == JNI_TRUE) { }
So, I now have a jobject which I know is a Boolean (note the upper case B) - The question is, what is the most efficient way (considering I already have the jobject in my native code) to convert this to a bool
. Typecasting doesn't work which makes sense.
Although the above example is a Boolean I also want to convert Character->char, Short->short, Integer->int, Float->float, Double->double.
(Once i've implemented it I will post an answer to this which does Boolean.booleanValue())
You have two choices.
Option #1 is what you wrote in your self-answer: use the public method defined for each class to extract the primitive value.
Option #2 is faster but not strictly legal: access the internal field directly. For Boolean, that would be Boolean.value. For each primitive box class you have a fieldID for the "value" field, and you just read the field directly. (JNI cheerfully ignores the fact that it's declared private. You can also write to "final" fields and do other stuff that falls into the "really bad idea" category.)
The name of the "value" field is unlikely to change since that would break serialization. So officially this is not recommended, but in practice you can get away with it if you need to.
Either way, you should be caching the jmethodID / jfieldID values, not looking them up every time (the lookups are relatively expensive).
You could also use the less expensive IsSameObject function rather than IsInstanceof, because the box classes are "final". That requires making an extra GetObjectClass call to get valueObject's class, but you only have to do that once before your various comparisons.
BTW, be careful with your use of "char". In your example above you're casting the result of CallCharMethod (a 16-bit UTF-16 value) to a char (an 8-bit value). Remember, char != jchar (unless you're somehow configured for wide chars), long != jlong (unless you're compiling with 64-bit longs).
This is the solution I'm going to use if I get no more input. Hopefully it isn't this difficult but knowing JNI i'm thinking it might be:
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);
}
In general, I write jni for the better performance. How to gain the better performance ? Using asm, primitive types and few method call. I suggest that design your method return type can use in c/c++, such as jint, jlong, jboolean, jbyte and jchar etc.
The redundant function call and convert will make inefficient and unmaintainable implementation.
精彩评论