JNI基础简介

简介: JNI系列入门连载,开启JNI学习之旅吧。

导读

在前面的几篇文章中,笔者介绍了C++中的指针、引用、智能指针、多线程、类型转换、异常处理等相关知识点,如果想要熟练掌握,并能在实际项目中运用,光是看肯定是毫无用处,纸上谈兵永远比不上脚踏实地的实在。。。

以下是前几篇文章的回顾:
C++之RVO返回值优化
C++之const关键字
C++之指针扫盲
C++之智能指针
C++之指针与引用
C++之右值引用
C++之类型转换
C++之多线程一
C++之多线程二
C++之异常处理

从今天开始文章的内容将是一系列JNI入门的相关文章。

JNI

JNI是Java Native Interface的缩写,俗称Java本地接口,是Java语言提供的用于Java和C/C++相互沟通的机制,Java可以通过JNI调用本地的C/C++代码,本地的C/C++的代码也可以通过JNI调用Java代码。

那什么场景下可能会用到JNI呢?
1、需要提升性能时,比如说做一些底层的开发,例如音视频处理之类的,通常都会用到JNI。
2、增加破解难度,例如需要提升代码的保护级别,需要将一些敏感信息放到底层隐藏起来。
3、需要使用到一些较为成熟的底层C/C++库时。

NDK

要在安卓上使用JNI就需要用到NDK,而NDK一系列工具的集合,它提供了一系列的工具帮助开发者快使得C/C++代码能够交叉编译生成可在安卓系统上运行的动态库库或者静态库。例如我们想要将基于C的音视频处理库FFmpeg移植到安卓平台上使用的话就需要用到NDK进行交叉编译。

动态库和静态库

1、静态库

静态库是指在链接阶段,编译器将汇编生成的.o目标文件与库文件一起链接打包到可执行文件中,或者说一起链接生成最后的可执行文件。因此对应的链接方式称为静态链接。

因为静态库是在编译期间连接库文件的,所以静态库存在着可执行文件体积较大,更新维护不方便等问题。

2、动态库

动态库又叫共享库,或动态链接库。动态库在程序编译时并不会被链接到目标代码中,而是在程序运行时才被载入,不同的应用程序如果要调用同一个库,在内存中只需要有一份该共享库即可,这样就规避了空间浪费的问题。而且动态库是在程序运行时才被载入,所以相对静态库来说动态库还具有更新、部署方便等优点。
正因为动态库的这些优点,所以目前的大多数的SDK普遍才有动态库的方式。

一个简单的JNI函数

我们使用Android Studio新建一个Native C++工程,系统将自动为我们创建一个最简单的JNI函数,当然不同的包名,生成的JNI函数名不一样,例如:

extern "C" JNIEXPORT jstring JNICALL
Java_com_fly_jnitest_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject obj) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

1、extern "C"
在JNI函数中首先出现的是extern "C",它是什么意思呢?这个其实写过C/C++代码的人估计都知道,就是为了在C++兼容C代码的,避免编绎器按照C++的方式去编绎C函数。
这是因为在C++中是支持函数重载的,所以在C++中函数的识别方式是通过:函数名,函数的返回类型,函数参数列表三者组合来完成的;而在C中是不支持函数重载的,因此编译C语言代码的函数时不会带上函数的参数类型,一般只包括函数名。因此需要通过extern "C"来使C++能够调用C写作的库文件。

2、jstring
这个没什么好说的,这个就是函数的返回值。

3、JNIEXPORT
JNIEXPORT是一个宏,它们在不同的平台有着不同的定义,它的主要作用是保证在本库中声明的方法,能够在其他项目中可以被调用。
例如attribute___((visibility ("default"))) 表示外部可见,类似于public修饰符 (即:可以被外部调用),而attribute___((visibility ("hidden")))表示隐藏,类似于private修饰符 (即:只能被内部调用)。

4、JNICALL
JNICALL也是一个宏,同样在不同的平台也有着不同的定义,用来表示函数的调用规范(如:__stdcall),目前在linux平台还是是空定义。

4、函数名
在上面的例子中函数名是Java_com_fly_jnitest_MainActivity_stringFromJNI,这是一个静态注册的函数名,它是与对于的Java方法有着对应关系的,他们的对应关系是:

Java_<包名>_<类名>_<方法名>

5、JNIEnv
JNIEnv 是指向JVM函数表的指针,JNIEnv代表了Java环境,通过JNIEnv就可以对Java端的代码进行操作,例如创建Java对象、访问Java对象方法、获取Java对象的属性等。
总之它是Java方法与C/C++方法沟通的桥梁。

需要注意的是:一个JNIEnv指针仅在其相关联的线程中有效。不能将这个指针从一个线程中传递给另一个线程,或者在多线程中缓存和使用它。Java虚拟机在同一个线程传递给本地方法相同的JNIEnv指针,但是从不同线程中调用本地方法时传递的是不同的JNIEnv指针。

6、jobject
jobject 代表了定义native函数的Java类的对象实例,如果对于的方法是一个静态方法,则是jclass。

数据类型映射关系

在JNI中每种Java的基本数据类型都与C/C++的基本数据类型形成映射关系。

下图展示的是Java中的基本数据类型与JNI中的基本数据类型的映射关系:

JNI基本数据映射

JNI以一种不透明的引用方式向原生代码传递对象,不透明的引用指的是指向Java虚拟机中内部数据对象的C语言指针。原生代码必须通过JNIEnv中定义的函数处理这些内部数据对象。例如对应java.lang.String的JNI对象是jstring.jstring引用的真实的值是与原生代码无关的。原生代码通过GetStringUTFChars来访问一个Java字符串的内容。

所有的JNI引用都是jobject类型。为了提高类型安全性以及保证使用的便利性,JNI定义了一系列引用类型,这些引用类型在概念上都是Jobject的子类型。这些子类型与Java语言中最常用的类型相关联。例如,jstring对应String, jobjectArray对应一个对象数组,下图是JNI引用类型以及与其所有子类型之间继承关系的列表:
JNI引用类型关系表

本篇作为一个开篇题,主要简单介绍了JNI中的一些基本的基础知识,关于JNI的更多用法我们将在后面的章节进行介绍。

目录
相关文章
|
6月前
|
存储 Java C++
[NDK/JNI系列02] JNI的设计原理与数据类型
[NDK/JNI系列02] JNI的设计原理与数据类型
46 0
[NDK/JNI系列02] JNI的设计原理与数据类型
|
6月前
|
Java API Android开发
[NDK/JNI系列01] NDK与JNI的基本概念与使用场景
[NDK/JNI系列01] NDK与JNI的基本概念与使用场景
68 0
|
6月前
|
C++
【C++】C++封装成DLL并调用(初学者快速入门)
【C++】C++封装成DLL并调用(初学者快速入门)
|
6月前
|
Rust Java Linux
【一起学Rust | 进阶篇 | jni库】JNI实现Java与Rust进行交互
【一起学Rust | 进阶篇 | jni库】JNI实现Java与Rust进行交互
196 0
|
Java API Android开发
JNI开发环境和基础配置
JNI开发环境和基础配置
401 0
JNI开发环境和基础配置
|
安全 Java C语言
java高级用法之:调用本地方法的利器JNA
java高级用法之:调用本地方法的利器JNA
java高级用法之:调用本地方法的利器JNA
|
Java Unix
要探索JDK的核心底层源码,那必须掌握native用法
要探索JDK的核心底层源码,那必须掌握native用法
194 0
要探索JDK的核心底层源码,那必须掌握native用法
|
Java C++ Android开发
JNI开发极简教程
JNI(Java Native Interface) Java调用C/C++,C/C++调用Java的一套API 前言: 学习JNI需要C/C++的相关知识,而且需要研究JNI手册.
2453 0