JNI C 反射谜题

JNI C Reflection puzzle

下面的所有代码都按预期工作,除了指示的崩溃行。 我花了几天时间摸索这段代码,检查并重新检查文档。如果有人能指出我遗漏的显而易见的事情,我会很高兴。

Main.java:

public class Main {
    public static void main(String[] args) {
        Test tst = new Test();
        System.out.println((String)tst.test());
    }
}

Test.java

public class Test {
    static { System.loadLibrary("test"); }
    public native Object test();
}

test.c

#include <jni.h>
JNIEXPORT jobject JNICALL Java_Test_test(JNIEnv *env, jobject thiz) {
    const char* out = "success";
    do {
        jclass cls_cls = (*env)->FindClass(env, "java/lang/Class");
        if ( !cls_cls ) { out = "FindClass"; break; }
        jmethodID mfn = (*env)->GetStaticMethodID(
            env, cls_cls, "forName", "(Ljava/lang/String;)Ljava/lang/Class;"
        );
        if ( !mfn ) { out = "GetStaticMethodID"; break; }
        // **** lines above succeed, line below segfaults ****
        jclass cls = (jclass) (*env)->CallStaticObjectMethod(
            env, cls_cls, mfn, "java.lang.String"
        );
        if ( (*env)->ExceptionCheck(env) ) { out = "CallStaticObjectMethod"; break; }
    } while ( 0 );
    (*env)->ExceptionClear(env);
    return (jobject) (*env)->NewStringUTF(env, out);
}

compile/exec

gcc -D_REENTRANT -fPIC -Wall -c test.c -o test.o -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux
gcc -D_REENTRANT -fPIC -Wall -shared -o libtest.so -O test.o
javac -Xlint:all Main.java
java -Xcheck:jni -Djava.library.path=. Main

预期结果,以纯 Java:

表示
Class<?> cls_cls = Class.class;
Method mfn = cls_cls.getDeclaredMethod("forName", String.class);
Class<?> cls = (Class) mfn.invoke(null, "java.lang.String");

要调用 Class.forName 方法,您应该将 java.lang.String 传递给它,而不是原始 const char*.

要从 C 字符串中获取 Java 字符串,请使用 NewStringUTF 函数:

jstring arg = (*env)->NewStringUTF(env, "java.lang.String");
jclass cls = (jclass) (*env)->CallStaticObjectMethod(
    env, cls_cls, mfn, arg
);

然后来自 Main.java 的 java 代码将打印:

success