java JNI RegisterNations在ClassLoader加载的类上不起作用。loadClass()
我在现有的C++应用程序中嵌入JVM,需要用类登记java的本地函数的实现。p>
考虑具有本机函数的这个简单类:
class Native {
static {
System.out.println("Class 'Native' static initializer called.");
}
public native int f(int i);
}
在JVM中,我运行的是OSGi,这就是为什么我需要使用Java代码(使用正确的类加载器)获取类,而不是从JNI加载它们。然而,为了简化这个例子,我省略了OSGi
我有四种不同的Java方法来获取C++中的jclass
值:
class Bridge {
public Class<?> getNativeClass1() throws ClassNotFoundException {
return getClass().getClassLoader().loadClass("org.example.Native");
}
public Class<?> getNativeClass2() throws ClassNotFoundException {
return Class.forName("org.example.Native", false, getClass().getClassLoader());
}
public Class<?> getNativeClass3() throws ClassNotFoundException {
final Class<?> clazz = getClass().getClassLoader()
.loadClass("org.example.Native");
clazz.getMethods();
return clazz;
}
public Class<?> getNativeClass4() throws ClassNotFoundException {
return Class.forName("org.example.Native", true, getClass().getClassLoader());
}
}
在C++中登记本地函数实现为^ {CD2>}:
JNIEnv* env = ...
jclass clazz = ...; // Calling one of the four methods above.
JNINativeMethod nativeMethod = {
(char*) "f", // Method name 'f'.
(char*) "(I)I;", // Signature 'int --> int'.
(void*) f // Pointer to C++ implementation of function.
};
env->RegisterNatives(clazz, &nativeMethod, 1);
根据获取Class<?>
实例所使用的方法,我会得到不同的结果:
getNativeClass1()
:加载类时(当然是在创建类的实例时),静态初始值设定项不会在类Native
中执行,并且本机实现未正确绑定。(在Java中调用本机函数会产生不正确的结果或使JVM崩溃。)李>getNativeClass2()
:同上李>getNativeClass3()
:当类被加载时,静态初始值设定项仍然没有在类Native
中被调用,但是本机实现被正确绑定,我可以成功调用f()
李>getNativeClass3()
:当类被加载并且本机实现被正确绑定时,静态初始值设定项在类Native
中被调用李>
因此ClassLoader.loadClass()
似乎以某种方式加载类,使其无法正确初始化,JNIEnv::RegisterNatives()
无法正常工作。然而,调用Class.getMethods()
将以某种方式初始化类(而不调用静态初始值设定项),以便绑定本机方法
另一方面,Class.forName(clazz, false, classLoader)
似乎与Class.loadClass()
返回未初始化的Class
实例完全一样
有人能解释这两者的区别吗
- 一个未初始化的类,如
getNativeClass1()
和getNativeClass2()
返回的类 - 一个部分初始化的类,如
getNativeClass3()
返回的类 - 完全初始化的类,如
getNativeClass4()
返回的类
在调用JNIEnv::RegisterNatives()
之前加载类的最方便的方式是什么
# 1 楼答案
根据documentation的说法:
loadClass(String)
:“调用此方法相当于调用loadClass(name,false)。”loadClass(String,boolean)
(强调添加):“如果使用上述步骤找到该类,且resolve标志为true,则此方法将在生成的类对象上调用resolveClass(class)方法。”这两种方法供需要在加载和链接之间进行操作的类加载器内部使用。我不确定为什么
loadClass(String)
被标记为公共,但可以说它不应该被标记为公共Class.forName()
,它使用上下文类加载器,并确保该类已准备好使用