JAVA JNI函数的注册过程详细介绍

JNI(Java Native Interface)是Java向底层语言(如C、C++)展示其本地方法(Native Method)能力的桥梁,因此在使用JNI时需要将Java方法与本地C/C++函数进行关联,这便是JNI函数的注册过程。

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函数的注册过程详细介绍