下面是一个演示(我省略了utils,它们只是检查是否存在异常并打印消息):
首先,它应该起作用:
c++部分:
jclass jClass_java_lang_System = env->FindClass("java/lang/System");
jmethodID jMethodID_java_lang_System_load = env->GetStaticMethodID(jClass_java_lang_System, "load", "(Ljava/lang/String;)V");
env->CallStaticVoidMethod(jClass_java_lang_System, jMethodID_java_lang_System_load, library_path);
没有例外,但是在那之后,调用一个本机方法 UnsatisfiedLinkError
.
第二次尝试,编写一个 Package 器方法:
public static void load(String path) {
System.load(path);
}
从c打过来++
jmethodID jMethodID_Driver_load = env->GetStaticMethodID(jClass_Driver, "load", "(Ljava/lang/String;)V");
env->CallStaticVoidMethod(jClass_Driver, jMethodID_Driver_load, library_path);
checkException(env);
它只是system.load的 Package 器,其他什么都没有,工作正常。本机呼叫工作正常。
如果要进行更多测试,但没有任何意义,请同时使用这两种方法:
jclass jClass_java_lang_System = env->FindClass("java/lang/System");
jmethodID jMethodID_java_lang_System_load = env->GetStaticMethodID(jClass_java_lang_System, "load", "(Ljava/lang/String;)V");
env->CallStaticVoidMethod(jClass_java_lang_System, jMethodID_java_lang_System_load, library_path);
if (!checkException(env)) std::cout << "Load by rt.jar no Exception" << std::endl;
jclass jClass_Driver = env->FindClass("Driver");
jmethodID jMethodID_Driver_load = env->GetStaticMethodID(jClass_Driver, "load", "(Ljava/lang/String;)V");
env->CallStaticVoidMethod(jClass_Driver, jMethodID_Driver_load, library_path);
checkException(env); // The first UnsatisfiedLinkError print by this util
// Second UnsatisfiedLinkError print by native method call, I omit it.
得到这个结果:
Load by rt.jar no Exception
java.lang.UnsatisfiedLinkError: Native Library XXXXX already loaded in another classloader
java.lang.UnsatisfiedLinkError: XXXXXXX
这使它更混乱,第一次尝试显示加载方式 java.lang.System-load()
不工作,但实际上已加载库。然后抛出重复加载异常。
然后倒序:
jclass jClass_Driver = env->FindClass("Driver");
jmethodID jMethodID_Driver_load = env->GetStaticMethodID(jClass_Driver, "load", "(Ljava/lang/String;)V");
env->CallStaticVoidMethod(jClass_Driver, jMethodID_Driver_load, library_path);
checkException(env);
jclass jClass_java_lang_System = env->FindClass("java/lang/System");
jmethodID jMethodID_java_lang_System_load = env->GetStaticMethodID(jClass_java_lang_System, "load", "(Ljava/lang/String;)V");
env->CallStaticVoidMethod(jClass_java_lang_System, jMethodID_java_lang_System_load, library_path);
if (!checkException(env)) std::cout << "Load by rt.jar no Exception" << std::endl;
结果是:
Load by wrapper no Exception
java.lang.UnsatisfiedLinkError: Native Library XXXX already loaded in another classloader
Result is - 2468
Result is - 2468
即使抛出重复加载异常,本机调用也能正常工作。
问题:发生了什么?如何解决?
1条答案
按热度按时间tsm1rwdh1#
加载本机库时
System.load()
vm将尝试将找到的任何jni函数绑定到它们的java对应函数,即声明本机方法的类。它只能在该类已加载时执行此操作。如果您随后加载类,您将拥有未绑定的本机方法,并且当您调用它们时,您将得到一个UnsatisfiedLinkError
.为了能够调用 Package 器方法,必须加载类,因此vm可以绑定本机方法。只需要打个电话
System.load()
,请确保vm已具有该类。也就是说,最好使用从类本身的静态初始值设定项加载本机库的常规方法。loadLibrary
还会找到静态链接的库。因此,如果您将jni函数与代码的其余部分分离,并将它们放入它们自己的库中,您就可以静态地链接它并使用它loadLibrary
名字很简单。