JNI(Java Native Interface)是Java向底层语言(如C、C++)展示其本地方法(Native Method)能力的桥梁,因此在使用JNI时需要将Java方法与本地C/C++函数进行关联,这便是JNI函数的注册过程。
JNI函数的注册流程如下:
1.在C/C++文件中,定义实现Java方法的本地函数。
2.使用javah
命令生成与本地函数对应的头文件。
3.在头文件中声明该本地函数为extern "C"
类型。
4.使用JNI_OnLoad()
函数将该本地函数通过RegisterNatives()
函数进行注册。
下面是两条示例说明:
示例一
我们想要在Java中调用一个用C实现的方法,该方法的函数原型为:
void print_str(const char* str);
C中的实现方式如下:
#include <jni.h>
void print_str(const char* str)
{
printf("%s", str);
}
在Java中调用该方法的代码为:
public class NativeCodeDemo {
static {
System.loadLibrary("print_str");
}
// Native方法
private static native void printStr(String str);
public static void main(String[] args) {
NativeCodeDemo.printStr("Hello World");
}
}
然后使用javah
命令生成头文件NativeCodeDemo.h
:
javah -classpath ./ NativeCodeDemo
生成的头文件如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class NativeCodeDemo */
#ifndef _Included_NativeCodeDemo
#define _Included_NativeCodeDemo
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: NativeCodeDemo
* Method: printStr
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_NativeCodeDemo_printStr
(JNIEnv *, jclass, jstring);
#ifdef __cplusplus
}
#endif
#endif
在头文件中,print_str
函数被声明为JNIEXPORT void JNICALL
类型。
接下来,在C中定义一个JNI_OnLoad
函数,该函数将该本地函数通过RegisterNatives()
函数进行注册,代码如下:
#include <jni.h>
#include "NativeCodeDemo.h"
void print_str(const char* str)
{
printf("%s", str);
}
JNIEXPORT void JNICALL Java_NativeCodeDemo_printStr
(JNIEnv *env, jclass clazz, jstring str)
{
const char* cstr = (*env)->GetStringUTFChars(env, str, NULL);
print_str(cstr);
(*env)->ReleaseStringUTFChars(env, str, cstr);
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
JNIEnv *env;
jclass clazz;
if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_8) != JNI_OK) {
return JNI_ERR;
}
clazz = (*env)->FindClass(env, "NativeCodeDemo");
if (clazz == NULL) {
return JNI_ERR;
}
const JNINativeMethod methods[] = {
{"printStr", "(Ljava/lang/String;)V", (void *)&Java_NativeCodeDemo_printStr},
};
if ((*env)->RegisterNatives(env, clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
return JNI_ERR;
}
return JNI_VERSION_1_8;
}
示例二
我们想在Java中调用一个用C++实现的函数,该函数的函数原型为:
int add(int a, int b);
我们可以定义一个类MyMath
,该类中的成员方法int add(int, int)
用C++实现:
#include <jni.h>
class MyMath {
public:
static int add(int a, int b) {
return a + b;
}
};
然后在Java文件中,定义一个native
方法,将其与MyMath
类中实现的add
方法关联:
public class MyMath {
static {
System.loadLibrary("my-math");
}
// Native方法
private static native int add(int a, int b);
// 测试方法
public static void main(String[] args) {
int result = MyMath.add(4, 6);
System.out.println(result);
}
}
使用javah
命令生成头文件MyMath.h
:
javah -classpath ./ MyMath
生成的头文件如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class MyMath */
#ifndef _Included_MyMath
#define _Included_MyMath
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: MyMath
* Method: add
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_MyMath_add
(JNIEnv *, jclass, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
在头文件中,add
函数被声明为JNIEXPORT jint JNICALL
类型。
定义实现该函数的C++代码如下:
#include <jni.h>
#include "MyMath.h"
class MyMath {
public:
static int add(int a, int b) {
return a + b;
}
};
JNIEXPORT jint JNICALL Java_MyMath_add(JNIEnv *env, jclass clazz, jint a, jint b)
{
return MyMath::add(a, b);
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
JNIEnv *env;
jclass clazz;
if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_8) != JNI_OK) {
return JNI_ERR;
}
clazz = (*env)->FindClass(env, "MyMath");
if (clazz == NULL) {
return JNI_ERR;
}
const JNINativeMethod methods[] = {
{"add", "(II)I", (void *)&Java_MyMath_add},
};
if ((*env)->RegisterNatives(env, clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
return JNI_ERR;
}
return JNI_VERSION_1_8;
}
以上就是Java JNI函数的注册过程的详细攻略。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JAVA JNI函数的注册过程详细介绍 - Python技术站