JNI的静态调用与动态注册

JNI的静态调用与动态注册

  • JNI的定义
  • JAVA调用JNI
  • JNI回调JAVA方法
  • 变量定义

JNI的定义

JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C跟C++)。Android系统中主要用于SystemServer的各种JAVA服务调用本地服务。

JAVA调用JNI

java调用JNI方法,都必须以带native关键字的方式定义在一个java文件中,JNI回调JAVA方法,则不需要带native关键字。

public class JniTest {
    //本地库编译的全名为libjnitest.so, loadLibrary方法只需加载库的名称
    static{
       System.loadLibrary("jnitest");
    }
    //另外还有一种库的加载方式,这种方式加载库需要使用库的绝对路径,
    //比如在Android系统中,需要加载系统中的库,则:
    //System.load("/system/lib/libxxx.so");

    //定义本地方法
    public native void set(int a);
    public native int  get();

    //定义JNI回调Java的方法
    public void callByJNI();  

    //定义JNI回调带int参数的java方法
    public void callByJNI(int i);
}
  • 静态注册
    静态注册中java的native方法与C/C++代码函数是通过Java_<包名><类名><方法名>这种方式对应的
    使用静态注册实现上述java文件中的本地方法如下:
#include <jni.h> 
int value;
void Java_com_test_jni_JniTest_set(JNIEnv* env, jobject thiz, jint a){
   value = a;
}

jint Java_com_test_jni_JniTest_get(JNIEnv* env, jobject thiz){
   return value;
}
  • 动态注册
    与静态注册不同的是,动态注册不受命名的限制。动态注册分为三步:
    1.定义本地方法与java方法对应的表,这里JNI提供了一个结构体JNINativeMethod来对应表。
    2.JNI_OnLoad方法触发:当java类调用System.loadLibrary或者System.load时触发JNI的此方法
    3.注册本地方法,使用JNIEnv结构体指针中的RegisterNatives方法来注册本地函数。
#include <jni.h>
#include <string>

static int mValue = 0;
void native_set(JNIEnv* env,jobject thiz,int value){
    mValue = value;
}

jint native_get(JNIEnv* env,jobject thiz){
    return mValue;
}

static JNINativeMethod method_tables[] = {
        {"set", "(I)V", (void *)native_set}, //{java中的native方法名,参数类型,JNI方法}
        {"get", "()I",  (void *)native_get},
};

static int registerNativeMethods(JNIEnv* env,
                                 const char* className,
                                 JNINativeMethod* jMethods,
                                 int numMethods) {
    jclass clazz;
    clazz = env->FindClass(className);
    if (clazz == NULL) {
        return JNI_FALSE;
    }
    if (env->RegisterNatives(clazz, jMethods, numMethods) < 0) {
        return JNI_FALSE;
    }
    return JNI_TRUE;
}

static int registerNatives(JNIEnv* env) {
    const char* jClassName = "com/test/jnitest/JniTest";//指定要注册的类
    return registerNativeMethods(env, jClassName, method_tables, sizeof(method_tables) / sizeof(method_tables[0]));
}

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
    JNIEnv* env = NULL;
    jint ret = -1;
    if (vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK) {
        goto fail;
    }
    assert(env != NULL);
    if (!registerNatives(env)) {//注册
        goto fail;
    }
    ret = JNI_VERSION_1_4;
    return ret;

    fail:
    return -1;
}

JNI回调JAVA方法

JNI回调JAVA方法,类似JAVA的类的反射调用方式, 接上述动态注册的例子,步骤如下:
1. 通过JNIEnv结构体指针找到对应的java class对象
2. 通过jclass对象找到class中对应方法的methodID
3. 根据方法理性,使用不同的JNI方法回调函数。

/*
 * 此处省略动态注册例子中其他代码...
 */

jint native_get(JNIEnv* env, jobject thiz){
    //回调不带参数的java方法
    jclass j_class = env->FindClass(env,"com/test/jni/JniTest");
    jmethodID  method = env->GetMethodID(env, j_class, "callByJNI","()V");
    env->CallVoidMethod(env, thiz, method);

    //回调带参数的java方法
    //jclass j_class = env->FindClass(env,"com/test/jni/JniTest");
    //jmethodID  method = env->GetMethodID(env, j_class, "callByJNI","(I)V");
    //env->CallVoidMethod(env, thiz, method, 666);
    return value
}

变量定义

Java基本数据类型对应JNI数据类型

Java类型 本地C类型
boolean jboolean
byte jbyte
char jchar
short jshort
int jint
long jlong
float jfloat
double jdouble
void void

参数类型对应

描述符 JNI类型 JAVA类型
V void void
Z jboolean boolean
I jint int
J jlong long
D jdouble double
F jfloat float
B jbyte byte
C jchar char
S jshort short
[I jintArray int[]
[F jfloatArray float[]
[B jbyteArray byte[]
[C jcharArray char[]
[S jshortArray short[]
[D jdoubleArray double[]
[J jlongArray long[]
[Z jbooleanArray boolean[]

猜你喜欢

转载自blog.csdn.net/zjfengdou30/article/details/81089643
今日推荐