最权威的文档请见JNI
在某些情况下,单独使用Java编程无法满足开发者的需求,这时可以使用JNI(Java Native Interface)来处理。常见的需要使用JNI的场景有:
(1)标准Java类库不支持应用程序所需的平台相关特性。
(2)存在其他语言编写的库,并且希望通过JNI使Java代码能够使用该库。
(3)用低级语言(如汇编)实现一小部分时间关键型代码。
通过JNI编程,可以使用native methods做到:
(1)创建、检查和更新Java对象(包括数组和字符串)。
(2)调用Java方法。
(3)捕获并抛出异常。
(4)加载类并获取类信息。
(5)执行运行时类型检查。
在C++中:
class _jobject {};
class _jclass : public _jobject {};
// ...
typedef _jobject *jobject;
typedef _jclass *jclass;
typedef union jvalue {
jboolean z;
jbyte b;
jchar c;
jshort s;
jint i;
jlong j;
jfloat f;
jdouble d;
jobject l;
} jvalue;
对于以下Java方法:
long f (int n, String s, int[] arr);
具有如下签名(signature):
(ILjava/lang/String;[I)J
JNI方法列表请见:Interface Function Table
(1)其中有对象操作方法如:
jobject NewObjectV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
其中参数:
env: JNI 接口指针,不能为null
clazz: Java类对象的引用,不能为null
methodID: 构造函数的MethodID,可以通过GetMethodID()获得
(2)其中有对象Fileld 访问方法如:
jfieldID GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig);
其中参数:
env: JNI 接口指针,不能为null
clazz: Java类对象,不能为null
name: 字段名的UTF-8 string, 不能为null
sig: 字段签名的UTF-8 string, 不能为null
…方法较多就不再继续罗列。
JVM有两种方法来查找native方法并将其与Java代码链接。第一种方法是以特定的命名方式命名native 函数,以便JVM能够找到它。另一种方法是使用JNI RegisterNatives()方法,RegisterNatives()使用作为参数传递的类注册本机方法。通过使用这种方法,我们可以随意命名C++函数。java.lang.Object的registerNatives()方法使用了第二种方法。让我们看看C语言中OpenJDK 8中java.lang.Object的registerNatives()方法实现:
static JNINativeMethod methods[] = {
{"hashCode", "()I", (void *)&JVM_IHashCode},
{"wait", "(J)V", (void *)&JVM_MonitorWait},
{"notify", "()V", (void *)&JVM_MonitorNotify},
{"notifyAll", "()V", (void *)&JVM_MonitorNotifyAll},
{"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone},
};
JNIEXPORT void JNICALL
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
{
(*env)->RegisterNatives(env, cls,
methods, sizeof(methods)/sizeof(methods[0]));
}
public class RegisterNativesHelloWorldJNI {
public native void register();
public native String sayHello();
public static void main(String[] args) {
RegisterNativesHelloWorldJNI helloWorldJNI = new RegisterNativesHelloWorldJNI();
helloWorldJNI.register();
helloWorldJNI.sayHello();
}
}
//c++注册实现
static JNINativeMethod methods[] = {
{"sayHello", "()Ljava/lang/String;", (void*) &hello },
};
JNIEXPORT void JNICALL Java_com_baeldung_jni_RegisterNativesHelloWorldJNI_register (JNIEnv* env, jobject thsObject) {
jclass clazz = env->FindClass("com/baeldung/jni/RegisterNativesHelloWorldJNI");
(env)->RegisterNatives(clazz, methods, sizeof(methods)/sizeof(methods[0]));
}
JNIEXPORT jstring JNICALL hello (JNIEnv* env, jobject thisObject) {
std::string hello = "Hello from registered native C++ !!";
std::cout << hello << std::endl;
return env->NewStringUTF(hello.c_str());
}
打印:
Hello from registered native C++ !!