JNI调用静态方法.类对象是必需的吗
JNI Invoking Static methods. Is the class object necessary?
开始使用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对象,这样做实际上没有开销,因为它不是对象的实际实例。
- 对RValue对象调用的LValue ref限定成员函数
- 检查哪个对象调用了另一个对象的对象方法
- 在 C++ 的 Switch Case 中创建对象后对对象调用方法
- 从 Base 引用对象调用派生类的成员
- 为什么为未删除的对象调用析构函数?
- Qt c++不会为所有对象调用move_slot.为什么?
- 使用在堆栈上创建的对象调用虚拟函数
- 使用基类对象调用Dervied Class函数
- C++:允许临时对象调用非常量成员函数的设计理念是什么?
- 从类中的对象调用类中的函数的最佳方法
- 派生对象调用的 Base 方法的模板推导
- 如何使用单个对象调用具有相同名称的两个类函数
- 是否可以从另一个类对象调用一个类函数而不继承第一个类
- 如果类没有任何成员变量,则通过临时对象调用类的成员函数的开销是多少?
- 如何对动态数组中的某些对象调用析构函数
- 如何从列表中存储的对象调用成员函数
- 从线程内的对象调用静态方法
- 从成员对象调用方法
- 当包含它的对象调用其析构函数时,unique_ptr是否未分配
- 从对象调用成员对象,错误:引用非常量值的初始值必须是左值