Android NDK与JNI基础

本文介绍了Android NDK和JNI的基础知识,包括NDK的定义和作用,JNI的命名规则,实现JNI的步骤,JNIEnv指针的功能、创建、释放和使用,以及JNI函数的类型和使用。同时,讲解了JNI数据类型、jobject和jclass的区别,以及如何通过JNI函数操作Java对象、成员域、方法等。此外,还涉及了异常处理、全局和局部引用、弱全局引用等概念。
摘要由CSDN通过智能技术生成

目录

什么是NDK

什么是JNI

JNI的命名规则

如何实现JNI

JNIEnv指针

JNIEnv的作用

JNIEnv的创建

JNIEnv的释放

了解JNI函数

jobject 与 jclass类型

JNI数据类型

基本类型对照表

引用类型对照表

签名机制

JNI函数

版本信息

操作类

异常

全局和局部引用

弱全局引用

操作对象

访问对象成员域

调用对象方法

访问静态域

调用静态方法

操作字符串

操作数组

注册本地方法

操作监视器(同步锁)

NIO支持

反射支持

Java虚拟机接口

JNI_OnLoad

JNI_OnUnload


什么是NDK

Android NDK 是一套工具集合,允许你使用C/C++语言来实现应用程序的部分功能。NDK本身其实就是一个交叉工作链,包含了Android上的一些库文件,然后,NDK为了方便使用,提供了一些脚本,使得更容易的编译C/C++代码。

什么是JNI

JNI,全称为Java Native Interface,即Java本地接口,JNI是Java调用Native 语言的一种特性。通过JNI可以使得Java与C/C++机型交互。即可以在Java代码中调用C/C++等语言的代码或者在C/C++代码中调用Java代码。

JNI的命名规则

JNIExport jstring JNICALL com_example_hellojni_MainActivity_stringFromJNI(JNIEnv* env, jobject obj) 

jstring                                是返回值类型
com_example_hellojni    是包名
MainActivity                     是类名
stringFromJNI                   是方法名

JNIExport 和 JNICALL 是定义在jni.h头文件中的宏定义,声明该JNI函数可从动态库导出和符合调用约定;
JNIEnv 一个接口指针,是JNI环境结构体指针(C语言版本),使用它能完成很多与java交互的操作;
jobject 表示Java层native方法的调用对象(此处是obj对象)。

如何实现JNI

JNI开发流程的步骤:

  • 第1步:在Java中先声明一个native方法
  • 第2步:编译Java源文件javac得到.class文件
  • 第3步:通过javah -jni命令导出JNI的.h头文件
  • 第4步:使用Java需要交互的本地代码,实现在Java中声明的Native方法(如果Java需要与C++交互,那么就用C++实现Java的Native方法。)
  • 第5步:将本地代码编译成动态库(Windows系统下是.dll文件,如果是Linux系统下是.so文件,如果是Mac系统下是.jnilib)
  • 第6步:通过Java命令执行Java程序,最终实现Java调用本地代码。

注:javah 是JDK自带的一个命令,-jni参数表示将class 中用到native 声明的函数生成JNI 规则的函数。

例:在Terminal下首先定位到src目录下,然后在输入

javah -jni com.example.hellojni.MainActivity

使用javah生成Native方法对应的Native函数声明,会发现所有的Native函数的第一个参数永远是JNIEnv指针,而第二个参数永远是jobject或jclass中的一个。JNIEnv指针指代何物?具有何种功能?jobject和jclass又有何区别?

JNIEnv指针

JNIEnv,顾名思义,指代了Java本地接口环境(Java Native Interface Environment),是一个JNI接口指针,指向了本地方法的一个函数表,该函数表中的每一个成员指向了一个JNI函数,本地方法通过JNI函数来访问JVM中的数据结构。Java可以创建多个线程,每个线程对应一个JNIEnv结构,所以JNI接口指针仅在当前线程中起作用。这意味着指针不能从一个线程进入另一个线程。

JNIEnv的作用

调用Java 函数:JNIEnv代表了Java执行环境,能够使用JNIEnv调用Java中的代码

操作Java代码:Java对象传入JNI层就是jobject对象,需要使用JNIEnv来操作这个Java对象

JNIEnv的创建

C 中的创建:JNIInvokeInterface是C语言环境中的JavaVM结构体,调用 AttachCurrentThread(JavaVM, JNIEnv*, void) 方法,能够获得JNIEnv结构体。

C++中的创建:_JavaVM是C++中JavaVM结构体,调用jint AttachCurrentThread(JNIEnv** p_env, void* thr_args) 方法,能够获取JNIEnv结构体。

JNIEnv的释放

C 中释放:调用JavaVM结构体JNIInvokeInterface中的(DetachCurrentThread)(JavaVM)方法,能够释放本线程的JNIEnv

C++ 中释放:调用JavaVM结构体_JavaVM中的jint DetachCurrentThread(){ return functions->DetachCurrentThread(this); } 方法,就可以释放 本线程的JNIEnv

了解JNI函数

首先看看什么是JNI函数。JNI函数就是在native层定义的本地函数,对应于在java层使用native关键字声明的方法的。直白的说,就是在Java层声明,C/C++语言实现的。当然,这个函数并不一般,它会通过JNI某种机制与Java层的方法进行关联,使得Java层代码可以很方便的调用它。

jobject 与 jclass类型

jobject 与 jclass 通常作为 JNI函数 的第二个参数,当所声明Native方法是静态方法时,对应参数jclass,因为静态方法不依赖对象实例,而依赖于类,所以参数中传递的是一个jclass类型。相反,如果声明的Native方法时非静态方法时,那么对应参数是jobject 。为了能够在Native层访问Java中的类和对象,jobject 和 jclass 分别指代了其所指代的对象和类,进而访问成员方法和成员变量等。

JNI数据类型

由于Java语言与C/C++语言数据类型的不匹配,需要单独定义一系列的数据类型转换关系来完成两者之间的映射。

基本类型对照表

Java类型 JNI类型 描述
boolean jboolean 无符号8位
byte jbyte 无符号8位
char jchar 无符号16位
short jshort 有符号16位
int jint 有符号32位
long jlong 有符号64位
float jfloat 有符号32位
double jdouble 有符号64位
void void 无类型

引用类型对照表

Java类型 JNI类型 描述
boolean[] jbooleanArray 布尔类型数组
byte[] jbyteArray 字节数组
char[] jcharArray 字符型数组
short[] jshortArray 短整型数组
int[] jintArray 整型数组
long[] jlongArray 长整型数组
float[] jfloatArray 单精度浮点型数组
double[] jdoubleArray 双精度浮点型数组
All objects jobject 任何 Java 对象
Object[] jobjectArray 对象数组
java.lang.Class jclass Class 对象
java.lang.String jstring 字符串对象
java.lang.Throwable jthrowable Throwable 对象

签名机制

函数签名由字符串组成,第一部分是包含在圆括号()里的,用来说明参数类型,第二部分则跟的是返回值类型,[表示数组

。比如”([Ljava/lang/Object;)Z”就是参数为Object[],返回值是boolean的函数的签名。下表列出类型与签名标识的对应关系:

Java类型 类型标识
boolean Z
byte B
char C
short S
int I
long J
float F
double
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值