JNI GetLongField失败," jni对类java.lang.Class"的对象无效。

时间:2016-07-08 07:09:42

标签: java android android-ndk java-native-interface

java代码:

public class Foo {
    private long i = 0;
    void printI() {
        nativePrintI();
    }      
    private native static void nativePrintI();
}

JNI代码:

JNIEXPORT void JNICALL Java_com_aliyun_livestream_Publisher_nativeRelease
    (JNIEnv *env, jobject obj) {
    jclass cls = env->GetObjectClass(obj);;
    jfieldID iField = env->GetFieldID(cls, "i", "J");
    jlong i = env->GetLongField(obj, iField);
    printf("%lld\n", i);
}

我的被叫者是这样的:

Foo foo = new Foo();
foo.printI();

有时它运行正常,但有时它失败了消息"" jni对类java.lang.Class"

的对象无效

2 个答案:

答案 0 :(得分:5)

当您将native方法声明为static时,相应的JNI函数将收到JNIEnv*jclass,以及您指定的任何其他参数(在此案例无)。 jclass参数是对调用该方法的类的引用 这与您在Java中进行的调用没有什么不同;当你调用static方法时,它将在类上调用,而不是从该类实例化的对象。

另一方面,非静态native方法将使用JNIEnv*jobject调用JNI函数,其中jobject是对象的引用在哪个方法被调用。

在C / C ++中,jobjectjclass都是指针,因此您可以将一个指定给另一个,但是当您尝试将它们传递给Java时/ JNI函数这些指针指向的底层值是多少 GetObjectClassGetLongField期望您将jobject传递给他们,因此jclass案例中的static将无效。

如果需要jobject,请在Java中将该方法声明为非静态方法。如果需要jclass,请在Java中将该方法声明为static。如果您想要两者,请将其声明为非静态,以便您收到jobject,然后您可以在其上调用GetObjectClass

答案 1 :(得分:1)

使用Can I know the name of the class that calls a JNI C method?

中的摘录
jclass cls = env->GetObjectClass(obj);

// First get the class object
jmethodID mid = env->GetMethodID(cls, "getClass", "()Ljava/lang/Class;");
jobject clsObj = env->CallObjectMethod(obj, mid);

// Now get the class object's class descriptor
cls = env->GetObjectClass(clsObj);

// Find the getName() method on the class object
mid = env->GetMethodID(cls, "getName", "()Ljava/lang/String;");

// Call the getName() to get a jstring object back
jstring strObj = (jstring)env->CallObjectMethod(clsObj, mid);

// Now get the c string from the java jstring object
const char* str = env->GetStringUTFChars(strObj, NULL);

// Print the class name
printf("\nCalling class is: %s\n", str);

// Release the memory pinned char array
env->ReleaseStringUTFChars(strObj, str);

事实证明,当Calling类名称为" java.lang.Class"时,GetLongField失败。但是,当呼叫类名称为" Foo"时,GetLongField成功。

可能是由于Java的GC机制。因为函数nativePrintI被定义为静态函数。 Java有时会在没有有效实例的情况下调用它。

所以将nativePrintI更改为private native void nativePrintI();可以解决问题。