JNI简介

# 一、简介

## 1. 什么是JNI

JNi就是java调用本地方法的技术,最简单的来说,java运行一个程序需要要和不同的系统平台打交道,在windows里就是和windows平台底层打交道,mac就是要和mac打交道,jvm就是通过大量的jni技术使得java能够在不同平台上运行。使用了这技术的一个标志就是native,如果一个类里的一个方法被native修饰,那就说明这个方法是jni来实现的,他是通过本地系统api里的方法来实现的。当然这个本地方法可能是c或者C++,当然也可能是别的语言。jni是java跨平台的基础,jvm通过在不同系统上调用不同的本地方法使得jvm可以在不同平台间移植。

![JNI UML](https://img-blog.csdnimg.cn/20191121133527673.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIyMDkwMDcz,size_16,color_FFFFFF,t_70)

上图可以看到,JNI相当于是一层翻译器,JAVA想要调用本地方法,通过JNI解释,执行,同样的,本地方法想要调用JAVA方法,也是通过JNI来进行的。

## 2. JNI定义

-  定义:Java Native Interface,即JAVA本地接口

-  作用:使JAVA语言和其他编程语言(C、C++等)进行交互

-  JNI是JAVA调用NATIVE语言的一种特性

-  实际中驱动都是C和C++开发的,通过JNI,JAVA可以调用C/C++实现的驱动,从而扩展JAVA虚拟机的能力。另外,在高效率的数学运算、游戏的实时渲染、音视频的编码和解码等方面,一般都是用C开发的

# 二、NDK是什么

## 1.定义

- 定义:Native Development Kit,是android的一个开发工具包

- 作用:快速开发C、C++的动态库,并自动将so和应用一起打包成APK

- 提供了把.so和.apk打包的工具

- NDK提供的库有限,仅拥有算法效率和敏感问题

- 提供了交叉编译器,用于生成特定的CPU平台动态库

## 2.特点

- 运行效率高

- 代码安全性高

- 功能扩展性好

- 易于代码复用和移植

# 三、JNI和NDK的关系

## 1. NDK是Android中实现JNI的手段

JNI是实现JAVA调用C/C++的途径,NDK是android中调用本地方法的桥梁。所以可以说NDK是Android中实现JNI的手段, 即在Android的开发环境中,通过NDK从而实现JNI功能。 JAVA的优点是跨平台,和操作系统之间的调用由JVM完成,但是一些和操作系统相关的操作就无法完成,JNI的出现刚刚弥补了这个缺陷,也完善了JAVA语言,将JAVA扩展的更强大。


我们需要了解的是,每个平台编译的文件后缀是不一样的

平台 | 后缀

--------| ---------

android、linux |  .so 

windows |  .dll 

mac |  .a 

# 四、JNI动态注册和静态注册

为了不让大家枯燥的看这些概念,我们通过两个例子来了解静态注册和动态注册。(我们在windows中运行的,所以下面例子中生成的库文件是.dll类型的)

## 1. 静态注册

<a href="https://blog.csdn.net/qq_22090073/article/details/103182987" >点击这里查看具体使用方法</a>

- 在Java中声明Native方法(即需要调用的本地方法)

- 编译上述JAVA源文件javac(得到.class文件)

- 通过javah命令导出JNI的头文件(.h文件)

- 使用JAVA需要交互的本地代码,实现在JAVA中声明的Native方法

- 编译.so库文件

- 通过JAVA命令执行JAVA程序,最终实现JAVA调用本地代码


## 2. 动态注册

在此之前我们一直在jni中使用的 Java_PACKAGENAME_CLASSNAME_METHODNAME 来进行与java方法的匹配,这种方式我们称之为静态注册。

而动态注册则意味着方法名可以不用这么长了,我们也不必再通过javah命令生成头文件,在android aosp源码中就大量的使用了动态注册的形式

```

//Java:

native void dynamicNative();

native String dynamicNative(int i);


//C++:

void dynamicNative1(JNIEnv *env, jobject jobj){

LOGE("dynamicNative1 动态注册");

}

jstring dynamicNative2(JNIEnv *env, jobject jobj,jint i){

return env->NewStringUTF("我是动态注册的dynamicNative2方法");

}

//需要动态注册的方法数组

static const JNINativeMethod mMethods[] = {

{"dynamicNative","()V", (void *)dynamicNative1},

{"dynamicNative", "(I)Ljava/lang/String;", (jstring *)dynamicNative2}

};


//需要动态注册native方法的类名

static const char* mClassName = "com/dongnao/jnitest/MainActivity";

jint JNI_OnLoad(JavaVM* vm, void* reserved){

JNIEnv* env = NULL;

//获得 JniEnv

int r = vm->GetEnv((void**) &env, JNI_VERSION_1_4);

if( r != JNI_OK){

  return -1;

}

jclass mainActivityCls = env->FindClass( mClassName);

// 注册 如果小于0则注册失败

r = env->RegisterNatives(mainActivityCls,mMethods,2);

if(r != JNI_OK )

{

  return -1;

}

return JNI_VERSION_1_4;

}

```

## 3. 在IDE中调用本地库的时候,需要指定java.library.path属性

- 点击右上角的Edit Configuration

![在这里插入图片描述](https://img-blog.csdnimg.cn/20191121152552235.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIyMDkwMDcz,size_16,color_FFFFFF,t_70)

- 在Configuration标签页中,将VM options项中的-Djava.library.path属性指定到你的dll库目录下:

![在这里插入图片描述](https://img-blog.csdnimg.cn/20191121152742129.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIyMDkwMDcz,size_16,color_FFFFFF,t_70)

## 4. 动态注册,我们需要指定java方法的方法名,方法签名,来与C函数建立关联,java方法签名是怎么获取的呢?


**下面这张表对应了java方法返回值的签名:**

![在这里插入图片描述](https://img-blog.csdnimg.cn/20191121153433443.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIyMDkwMDcz,size_16,color_FFFFFF,t_70)


**我们也可以通过命令来查看:**

```

使用javap命令:

javap -s -p JniTes.class


E:\java\JniTest1\src>javap -s -p Register

Compiled from "Register.java"

public class Register {

  public Register();

    descriptor: ()V


  public native java.lang.String HelloWorld();

    descriptor: ()Ljava/lang/String;

}


```

上面是终端打印出来的, 其中:

()V,代表的是Register的构造函数,是Void类型的;

()Ljava/lang/String; 是我们的本地方法,类型是String。

**特别还要注意的是String后面的分号,千万不要忘记了。**

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355