我在现有的C ++应用程序中嵌入了JVM,需要在类中注册本机Java函数的实现。
考虑这个带有原生函数的简单类:
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 ++中为Native.f()
注册本机函数实现,我调用:
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
中调用静态初始化程序,但本机实现 绑定正确,我可以调用{{1}成功。f()
:当加载类并且本机实现 绑定正确时,在类getNativeClass3()
中调用静态初始化程序 。因此,似乎Native
以某种方式加载类,因此未正确初始化,ClassLoader.loadClass()
将无法正常工作。但是,调用JNIEnv::RegisterNatives()
将以某种方式初始化类(不调用静态初始化程序),以便绑定本机方法。
另一方面,Class.getMethods()
似乎与Class.forName(clazz, false, classLoader)
完全一样,返回未初始化的Class.loadClass()
实例。
任何人都可以解释
之间的区别Class
和getNativeClass1()
getNativeClass2()
getNativeClass3()
在调用getNativeClass4()
之前加载类的最便携方法是什么?
答案 0 :(得分:3)
所以似乎ClassLoader.loadClass()以某种方式加载类,因此没有正确初始化
loadClass(String)
:“调用此方法相当于调用loadClass(name,false)。”
loadClass(String,boolean)
(强调添加):“如果使用上述步骤找到类,并且resolve标志为true ,则此方法将调用resolveClass(Class)方法生成的Class对象“
这两种方法供类加载器内部使用,需要在加载和链接之间执行某些操作。我不确定为什么loadClass(String)
被标记为公开,但可以说它不应该是。
在调用
之前加载类的最便携方法是什么
Class.forName()
,它使用上下文类加载器并确保该类可以使用。