JNI编程 入门级

jni编程可以在java端调用其他编程语言来为自己的应用服务,做java语言很难甚至做不到的事,功能强大可想而知。

java端数据类型 —> jni端数据类型

 1. 常用数据类型

 boolean ---> Z
 int     ---> I
 float   ---> F
 double  ---> D
 long    ---> J
 byte    ---> B
 char    ---> C
 void    ---> V

 2. object数据类型

 L开头,然后以/分隔类路径,后面再加;
 例:String ---> Ljava/lang/String;

 3. Array数据类型

 以 [ 开头,跟着object数据类型签名
 例: int[] ---> [I
     int[][] ---> [[I

方法签名

(参数列表)返回值数据类型
例: public void set(int i1, int i2) ---> (II)V

获取jclass

- jclass jclass = env->FindClass("object完整类名");
- jclass jclass = env->GetObjectClass(jobject);

获取jmthodId

在jni端对java端对象的成员方法操作,必须要获取到这个方法的jmthodId

jmethodID methodId =  env->GetMethodID(jclass, "方法名", "方法签名");//获取非静态方法
jmethodID methodId2 = env->GetStaticMethodID(jclass, "方法名", "方法签名");//获取静态方法

获取object构造方法签名:jmethodID methodIdCtr = env->GetStaticMethodID(jclass, "<init>", "方法签名");

jni端创建java端的对象

本质上是在java端创建对象,jni端持有一个对java端的引用,通过引用来操作这个对象。

jobject obj = env->NewObject(jclass, jmethodIdCtr,...);//可传入构造参数

jni获取java端成员变量

//非静态变量
jfieldID fieldId =  env->GetFieldID(jclass, "变量名", "变量类型签名");
jobject field =  env->GetObjectField(jobject, fieldId);

//静态变量
jfieldID staticFieldId = env->GetStaticFieldID(jclass, "变量名", "变量类型签名");
env->GetStaticObjectField(jclass, fieldId);

jni修改java端成员变量

//非静态变量
jfieldID fieldId =  env->GetFieldID(jclass, "变量名", "变量类型签名");
env->SetObjectField(jobject, fieldId, value);

//静态变量
jfieldID staticFieldId = env->GetStaticFieldID(jclass, "变量名", "变量类型签名");
env->SetStaticObjectField(jclass, staticFieldId, value);

jni端调用java端成员方法

//非静态方法调用
jmethodID methodId =  env->GetMethodID(jclass, "方法名", "方法签名");
env->CallIntMethod(jobject, methodId, ...);//传入参数列表

//静态方法调用
jmethodID methodId2 = env->GetStaticMethodID(jclass, "方法名", "方法签名");
env->CallStaticObjectMethod(jclass, methodId2, ...);

jni端数组的创建

//arrayLength: 数组大小
jobjectArray objectArray = env->NewObjectArray(arrayLength, jclass, NULL);

//为数组中元素赋值
env->SetObjectArrayElement(objectArray, index, value);

jni函数中也为一些简单数据类型数组提供创建方法:

env->NewIntArray(arrayLength);
env->NewBooleanArray(arrayLength);
...
...

jni端访问java端数组

jfieldID fieldId =  env->GetFieldID(jclass, "变量名", "变量类型签名");
jobjectArray objectArray =  env->GetObjectField(jobject, fieldId);
jobject object =  env->GetObjectArrayElement(objectArray, index);

//修改元素
env->SetObjectArrayElement(objectArray, index, value);

如果想要缓存jclass,必须将其存在GlobalRef中

jclass classs = (jclass)env->NewGlobalRef(env->FindClass("object完整类名"));

globaleRef, localRef, weakGlobaleRef

JNI支持三种引用:局部引用、全局引用、弱全局引用。

① 局部引用

会阻止GC回收掉引用的VM对象;
会在本地方法返回时自动销毁,一般无需用户主动销毁。但是如果在for循环中创建局部引用,则需要手动销毁:

env->DeleteLocalRef(jobject);

因为局部引用会存放在一个引用表中,这个表存储的引用是有限的,创建大量的localRef而不及时销毁,引用表很可能会溢出。

② 全局引用

会阻止GC回收掉引用的VM对象;
必须手动调用:

env->DeleteGlobalRef(jobject);

销毁引用。

③ 弱全局引用

不会阻止GC回收掉引用的VM对象;
必须手动调用:

env->DeleteWeakGlobalRef(jobject);

销毁引用。

④ 比较两个引用是否引用了同一个VM对象

env->IsSameObject(ref, ref2);

JNI动态注册


#define JNIREG_CLASS "调用native方法的java类名"

//动态注册的方法
jstring cppGetStringFromJni(JNIEnv *env, jclass clazz)
{
    char* str = "hello world from C \n";
    return env->NewStringUTF(str);
}

//动态注册表
static JNINativeMethod cpp_g_methods[] = {
    { "java端声明的Native方法", "()Ljava/lang/String;", (void*)cppGetStringFromJni },
};

static bool cppRegisterNativeMethods(JNIEnv* env, const char* className,
    JNINativeMethod* g_methods, int numMethods)
{
    jclass clazz;
    clazz = env->FindClass(className);
    if (clazz == NULL) {
        return false;
    }
    if (env->RegisterNatives(clazz, g_methods, numMethods) < 0) {
        return false;
    }

    return true;
}

static bool cppRegisterNatives(JNIEnv* env)
{
    if (!cppRegisterNativeMethods(env, JNIREG_CLASS, cpp_g_methods, sizeof(cpp_g_methods) / sizeof(cpp_g_methods[0])))
        return false;

    return true;
}


JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) {
        return -1;
    }
    assert(env != NULL);

    if (!cppRegisterNatives(env)) {
        return -1;
    }

    result = JNI_VERSION_1_4;

    return result;
}

猜你喜欢

转载自blog.csdn.net/qq_15692039/article/details/77163031