JNI RegisterNatives不适用于ClassLoader.loadClass()加载的类

时间:2013-01-14 13:28:27

标签: java java-native-interface

我在现有的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()实例。

任何人都可以解释

之间的区别
  1. 未初始化的类,例如ClassgetNativeClass1()
  2. 返回的类
  3. 部分初始化的类,如getNativeClass2()
  4. 返回的类
  5. 完全初始化的类,如getNativeClass3()
  6. 返回的类

    在调用getNativeClass4()之前加载类的最便携方法是什么?

1 个答案:

答案 0 :(得分:3)

  

所以似乎ClassLoader.loadClass()以某种方式加载类,因此没有正确初始化

根据documentation

loadClass(String):“调用此方法相当于调用loadClass(name,false)。”

loadClass(String,boolean)(强调添加):“如果使用上述步骤找到类,并且resolve标志为true ,则此方法将调用resolveClass(Class)方法生成的Class对象“

这两种方法供类加载器内部使用,需要在加载和链接之间执行某些操作。我不确定为什么loadClass(String)被标记为公开,但可以说它不应该是。

  

在调用

之前加载类的最便携方法是什么

Class.forName(),它使用上下文类加载器并确保该类可以使用。