JNI调用静态方法.类对象是必需的吗

JNI Invoking Static methods. Is the class object necessary?

本文关键字:对象 调用 静态方法 JNI      更新时间:2023-10-16

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

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

动机是:如果它确实是合法的,我将不必缓存类对象以用于后续对静态方法的调用(同时记住调用NewGlobalRef…)。缓存jmethodID就足够了。

否,用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将使用您提供的类指针,并假定它是由加载的类返回的无效指针。但由于它为null,系统将segfault。

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

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对象,这样做实际上没有开销,因为它不是对象的实际实例。