5分钟理解Android中的JNI原理!!!

Android中的JNI原理

  • 一.Native方法的注册
    • 1.静态注册
      • 1)静态注册的原理
      • 2)静态注册的方法
      • 3)静态注册的缺点
    • 2.动态注册
      • 1)动态注册的方法
      • 2)解析AndroidRuntime::registerNativeMethods函数
  • 二.数据类型的转换
    • 1.基本数据类型的转换
    • 2.引用数据类型的转换
    • 3.引用数据类型的继承关系
  • 三.方法签名
    • 1.JNI方法签名的格式
  • 四.解析JNIEnv
  • 五.JNI的引用类型
    • 1.本地引用
    • 2.全局引用
    • 3.弱全局引用

        JNI(Java Native Interface)是Java本地接口,用来与其他的语言进行通信。通常情况下,当需要节省程序的运行时间时,会选择用C语言进行开发,用Java调用C语言实现一些功能。或者代码的核心算法、密钥等,也会保存在C语言的代码中,以提高代码的安全性。

一.Native方法的注册

1.静态注册

1)静态注册的原理

        根据方法名,将java方法和JNI函数建立关联。

2)静态注册的方法

        i)在项目中创建Test.java

package com.example;
public class Test{
   static{
      System.loadLibrary(“test_jni”);
   }
   public native void test();
}

        ii)打开命令行,进入项目的src/main/java目录下,执行

javac com/example/Test.java
javah com.example.Test

        会在当前目录下,生成com_example_Test.h文件。在com_example_Test.h文件中,生成了一个名为Java_com_example_test的函数。
        iii)当在Java中调用test方法时,JNI会寻找Java_com_example_test函数,找到后为Java方法和JNI的函数建立联系,完成静态注册。

3)静态注册的缺点

        i)JNI层的函数名过长。
        ii)声明Native方法的类需要用javah生成头文件。
        iii)初次调用Native方法时需要建立联系,影响效率。

2.动态注册

        JNI中有一种结构JNINativeMethod,用来记录Java的Native方法和JNI方法的关联关系,他在jni.h中定义:

Typedef struct{
   const char* name;//java方法的名字
   const char* signature;//java方法的签名信息
   void* fnPtr;//JNI中对应的方法指针
} JNINativeMethod;

1)动态注册的方法

        i)创建JNINativeMethod数组:

static const JNINativeMethod methods[] = {
   {“test1”,()v”,(void *)com_example_Test_test1},
   {“test2”,()v”,(void *)com_example_Test_test2},
   {“test3”,()v”,(void *)com_example_Test_test3},
   {“test4”,()v”,(void *)com_example_Test_test4}
};

        ii)调用AndroidRuntime::registerNativeMethods函数完成注册。

2)解析AndroidRuntime::registerNativeMethods函数

        AndroidRuntime.cpp中registerNativeMethods函数的执行过程:
        调用jniRegisterNativeMethods函数。

        JNIHelp.cpp中jniRegisterNativeMethods函数的执行过程:
        调用JNIEnv对象的RegisterNative函数完成JNI方法的注册。

二.数据类型的转换

1.基本数据类型的转换

Java Native Signature
byte jbyte B
char jchar C
double jdouble D
float jfloat F
int jint I
short jshort S
long jlong J
boolean jboolean Z
void void V

2.引用数据类型的转换

Java Native Signature
Object jobject L+classname+;
Class jclass Ljava/long/Class;
String jstring Ljava/lang/String;
Throwable jthrowable Ljava/lang/Throwable;
Object[] jobjectArray [L+classname+;
byte[] jbyteArray [B
char[] jcharArray [C
double[] jdoubleArray [D
float[] jfloatArray [F
int[] jintArray [I
short[] jshortArray [S
long[] jlongArray [J
boolean[] jbooleanArray [Z

3.引用数据类型的继承关系

5分钟理解Android中的JNI原理!!!_第1张图片

三.方法签名

        JNI通过引入方法签名来解决Java中方法重载导致的仅通过方法名无法找到方法的问题。

1.JNI方法签名的格式

        格式:(参数的签名格式…)返回值的签名格式

        java中提供javap命令自动生成方法签名:

javac C:/Test.java
javap –s –p C:/Test.class

四.解析JNIEnv

        JNIEnv是Native中Java环境的代表,用来调用Java的方法、操作Java的变量和对象。

        jni.h中JNIEnv的定义:

#if defined (_cplusplus)
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;
#endif

        JavaVM是虚拟机层在JNI层的代表,一个虚拟机进程只有一个JavaVM。通过JavaVM的AttachCurrentThread函数可以获取一个线程的JNIEnv,通过DetachCurrentThread函数释放资源。

        jni.h中_JNIEnv结构体的定义和部分函数:

struct _JNIEnv{
  const struct JNINativeInterface* functions;
#if defined (_cplusplus)
…
jclass FindClass (const char* name)
{ return functions->FindClass (this, name); }
…
  jmethodID GetMethodID (jclass clazz, const char* name, const char* sig)
  { return functions->GetMethodID (this, clazz, name, sig); }
  …
  jfieldID GetFieldID (jclass clazz, const char* name, const char* sig)
  { return functions->GetFieldID (this, clazz, name, sig); }
}

        _JNIEnv结构体内部包含了JNINativeInterface结构体。其定义的函数通过调用JNINativeInterface的函数来实现。

        jni.h中JNINativeInterface结构体的定义和部分函数:

sruct JNINativeInterface{
…
jclass (*FindClass) (JNIEnv*, const char* );
…
jmethodID (*GetMethodID) (JNIEnv*, jclass, const char*, const char*);
…
jfieldID (*GetFieldID) (JNIEnv*, jclass, const char*, const char*);}

        在JNINativeInterface结构体中定义了很多函数指针,通过这些函数指针,能够定位到虚拟机中的JNI函数表,实现JNI层在虚拟机中的函数调用。
        jfieldID和jmethodID用来代替Java类中的成员变量和方法。

五.JNI的引用类型

1.本地引用

        JNIEnv提供的函数所返回的引用基本上都是本地引用。
特点:
        1)Native函数返回时,本地引用自动释放。
        2)只在创建它的线程有效,不能跨线程使用。
        3)本地引用是JVM负责的引用类型,受JVM管理。
        可以通过DeleteLocalRef函数手动删除本地引用。

2.全局引用

特点:
        1)在Native函数返回时不会自动释放,需要手动释放,不会被GC回收。
        2)全局引用可以跨线程使用。
        3)全局引用不受JVM管理。
        可以通过NewGlobalRef函数来创建全局引用,通过DeleteGlobalRef函数释放全局引用。

3.弱全局引用

        弱全局引用是一种特殊的全局引用,和全局引用类似,弱全局引用可以被GC回收,回收之后会指向NULL。
        可以通过NewWeakGlobalRef函数来创建弱全局引用,通过DeleteWeakGlobalRef函数释放弱全局引用。在使用前需要使用JNIEvn的IsSameObject函数判断对象是否被回收。

你可能感兴趣的:(Android,java,android,android,studio)