有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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实例完全一样

有人能解释这两者的区别吗

  1. 一个未初始化的类,如getNativeClass1()getNativeClass2()返回的类
  2. 一个部分初始化的类,如getNativeClass3()返回的类
  3. 完全初始化的类,如getNativeClass4()返回的类

在调用JNIEnv::RegisterNatives()之前加载类的最方便的方式是什么


共 (1) 个答案

  1. # 1 楼答案

    So it seems that ClassLoader.loadClass() loads the class in a way so it is not properly initialized

    根据documentation的说法:

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

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

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

    and what is the most portable way to load a class before calling

    Class.forName(),它使用上下文类加载器,并确保该类已准备好使用