JNI调用静态方法。类对象是否必要?

时间:2015-04-23 18:36:41

标签: java c++ static java-native-interface

开始使用JNI从C ++调用静态java方法。具体来说,在获得jclass(使用FindClass)和jmethodID(使用GetStaticMethodID)之后,我继续调用CallStatic * MethodA例程系列。事实证明,所有这些例程都将jclass作为第一个参数。我开始想知道为什么需要类对象:因为所有信息都是在GetStaticMethodID中提供的,所以JVM无需使用类对象来完成工作。然后,我尝试在为第一个参数传递NULL时调用这些例程,并且调用成功。

我的问题:使用NULL类对象调用这些方法是否安全?

激励是:如果它确实合法,我将不必为后续调用静态方法缓存类对象(同时记住调用NewGlobalRef ....)。缓存jmethodID就足够了。

2 个答案:

答案 0 :(得分:3)

不,使用null(或无效)类指针调用此类静态函数绝对不安全

您的练习可能非常成功,例如,如果您的静态方法不引用任何其他静态类成员。但是,如果静态java方法引用任何其他静态成员,则JVM将需要有效的类指针。

示例:

采用这个简单的Java演示MyTest.java

public class MyTest {
    public static void mymain() {
        System.out.println("Hello, World in java from mymain");
        System.out.println(magic_counter);   // this will cause a segfault if 
    }                                        // class pointer is null 
    private static int magic_counter=777; 
}

并使用以下JNI C ++代码段调用它

... // JVM already loaded and initialised

jclass cls2 = env->FindClass("MyTest");
if(cls2 == nullptr) {
    cerr << "ERROR: class not found !";
}
else {
    cout << "Class MyTest found" << endl; 
    jmethodID mid = env->GetStaticMethodID(cls2, "mymain", "()V"); 
    if(mid == nullptr) 
        cerr << "ERROR: method void mymain() not found !" << endl; 
    else {
        env->CallStaticVoidMethod(cls2, mid);
        cout << endl;
    }
 }

调用GetStaticMethodID(nullptr, "mymain", "()V");会失败。因为当mymain()执行时,它将尝试访问静态变量magic_number。然后,JVM将使用您提供的类指针,并假设它是由加载的类返回的vaild指针。但是因为它是null,系统将是段错误的。

答案 1 :(得分:0)

,您不应该这样做,但是了解为什么您可以在某些情况下在调用静态方法时对类使用NULL的重要性很重要。至少在某些实现中。 我当然不是Java或jni的专家,但是如果您在https://android.googlesource.com/platform/art/+/master/runtime/jni/jni_internal.cc阅读源代码,则很明显,android jni不会引用CallStatic *方法的object参数...

static jboolean CallStaticBooleanMethod(JNIEnv* env, jclass, jmethodID mid, ...)

唯一的问题是,您不能保证在所有平台上的行为都可以,这仅仅是一种可能的实现方式的来源。

https://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/functions.html#wp15982提到该方法必须来自clazz,因此它的其他实现很有可能在进行调用之前进行辅助检查,即使这是在Java发行实现中可能无法实现的性能折衷。

值得注意的是,静态方法只能访问静态成员,因此此调用应该是安全的,但是jclass对象不是该类的实例,它是类定义,可以轻松地用于诊断信息等否则与实际调用该方法无关。安全并存储jclass对象,这样做实际上没有开销,因为它不是该对象的实际实例。