前言:

  一提到JNI,多数编程者会下意识地感受到一种无法言喻的恐惧。它给人的第一感觉就是"难",因为它不是单纯地在JVM环境内操作Java代码,而是跳出虚拟机与其他编程语言进行交互。

  你可能至今还没听说过这个技术,但是如果你是一个源码爱好者,或者有翻阅过JDK的一些源码,那你一定有接触过native方法。你是否因为查阅源码直到native方法戛然而止,但又由于它的空方法体,而对底层原理不知所以? 本文就带让你了解JNI。并通过一些案例来自己实现JNI的交互。

什么是JNI?

  JNI 全称 Java Native Interface。Java本地方法接口,它是Java语言允许Java代码与C、C++代码交互的标准机制。维基百科是这样解释的:“当应用无法完全用Java编程语言实现的时候,(例如,标准Java类库不支持的特定平台特性或者程序库时),JNI使得编程者能够编写native方法来处理这种情况”。这就意味着,在一个Java应用程序中,我们可以使用我们需要的C++类库,并且直接与Java代码交互,而且在可以被调用的C++程序内,反过来调用Java方法(回调函数)。

JNI的优点

  (1)JNI使得一些"过程"无需在Java中实现。例如,硬件敏感的,或者直接与操作系统API关联的命令。

  (2)由于使用底层的库,如图形,计算,各种类型的渲染等等,可以提高应用的运行性能。

  (3)已经有大量的库已经被实现,编程者可直接使用,不用再自行编写。这里的库指的是用其他编程语言实现的程序库,例如IO流或者线程等底层与OS交互的操作都是由C/C++实现的。

具体实现原理

  交互模式如图

  

要从Java调用C++函数,你需要进行以下操作: 

  1. 在Java类中创建一个native方法,此方法被本类其他方法调用

  2. 创建一个头文件,可以利用javah命令生成。

      在头文件中定义它的签名,如下所示:

  

  接口规范:

  JNIEXPORT <返回类型> JNICALL Java_<包名>_<类名>_<方法名>(JNIEnv*, <原对象引用>,<参数1>..<参数n>)

  • extern "C" 只被C++编译器识别,标明此方法利用C的函数命名协议来编译。
  • JNIEXPORT 是JNI必要的修饰符。
  • 数据类型带有"j"前缀的:jdouble,jobject..等是Java对象或类型在C++中的映射
  • JNIEnv* 指向JNI 环境,可以利用其调用所有JNI函数
  • jobject 引用当前Java对象

  3. 创建一个源文件,实现头文件中定义的接口。实现内容就是Java代码调用的C/C++代码。

  4. 编译头文件和源文件生成C/C++动态链接库 .so/.dll 文件

  5. 此native方法所在类,加载动态链接库。因为加载链接库要在执行native方法之前,所以此加载过程一般放在静态初始化块内执行。

  

  或

  

  总结一下,从Java代码中调用C/C++代码的流程

  (1)创建一个有native标识的方法,并且从其他Java方法调用它

  (2)Java编译器生成字节码

  (3)C/C++ 编译器生成动态库  .so文件(Linux)或 .dll文件(Windows)

  (4)运行程序,执行字节码

  (5)执行到loadLibary或load调用的时候,添加一个 .so文件到这个进程中

  (6)执行到native方法的时候,通过方法签名,在已打开的.so文件中进行搜索。

  (7)如果链接库内有对应方法,就会被执行,否则程序崩溃

  注:由于windows没找到生成动态链接库的工具,又不想安装C/C++开发环境,故以下案例都在以CentOS为操作系统的虚拟机内运行

  案例一:从Java调用C代码输出Hello World   

  此案例所有生成的所有文件如下:

  

  (1)创建JNI文件夹,创建Java文件如下:

  

  这里,我们定义了一个native方法,是个空方法体,我们在主函数内对其进行调用。

  注:这里使用的是System.load从绝对路径引用动态链接库,当然也可以使用loadLibrary方法,其是从java.library.path对应路径下搜索对应名称的库文件并加载。

  (2)编译HelloJNI.java文件,生成类文件

  

  (3)利用JDK提供的JNI命令工具,javah生成 .h头文件。

  

  注:发现Linux环境下,javah居然不能从当前文件夹扫描到类文件,需要指定类路径 其中 -cp 就是-classpath

  以下是利用javah生成的头文件。

  

  (4)创建HelloJNI.c文件,编写实现体

  

  (5)利用gcc生成动态链接库,注意我们这里有引用到jni.h这个头文件,此文件由JDK提供,另外jni.h还引用了jni_md.h这个文件。必须引入这两个头文件,才能通过编译。

  两个文件的所在地,本人JDK的安装路径在/usr/java下,每个人可能都不一样。

  

  

  在gcc命令内通过指定( -I 路径 )引入库所在的目录,利用前面前面的头文件和源文件编译成动态链接库 hello.so

  

  

  (6)运行java程序

  

  由图可知,我们成功调用了C的代码

【详解】JNI(Java Native Interface)(一)的更多相关文章

  1. 【详解】JNI (Java Native Interface) (二)

    案例二:传递参数给C代码,并从其获取结果 注:这里传递的参数是基本类型的参数,在C代码中有直接的映射类型. 此案例所有生成的所有文件如下: (1)编写案例二的Java代码,如下: 这里我们定义了一个n ...

  2. 【详解】JNI (Java Native Interface) (四)

    案例四:回调实例方法与静态方法 描述:此案例将通过Java调用的C语言代码回调Java方法. 要想调用实例对象的方法,需要进行以下步骤: 1. 通过对象实例,获取到对象类的引用  => GetO ...

  3. 【详解】JNI (Java Native Interface) (三)

    案例三:C代码访问Java对象的实例变量   获取对象的实例变量的步骤: 1. 通过GetObjectClass()方法获得此对象的类引用 2. 通过类引用的GetFieldID()方法获得实例变量的 ...

  4. Android Jni(Java Native Interface)笔记

    首先记录一个问题,关于如何用javah生成头文件. 为什么要生成头文件?在含有 static{ System.loadLibrary("hellojni"); } 这样代码的类下面 ...

  5. JNI(java Native Interface)

    参看: http://blog.csdn.net/xw13106209/article/details/6989415

  6. android 学习随笔二十七(JNI:Java Native Interface,JAVA原生接口 )

    JNI(Java Native Interface,JAVA原生接口) 使用JNI可以使Java代码和其他语言写的代码(如C/C++代码)进行交互. 问:为什么要进行交互? 首先,Java语言提供的类 ...

  7. JNI(Java Native Interface)

    一.JNI(Java Native Interface)        1.什么是JNI:               JNI(Java Native Interface):java本地开发接口   ...

  8. Java Native Interface 六JNI中的异常

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 在这里只讨论调用JNI方法可能会出现的异常, ...

  9. Java Native Interface 五 JNI里的多线程与JNI方法的注册

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 JNI里的多线程 在本地方法里写有关多线程的 ...

随机推荐

  1. SRM480

    250pt: 题意:给定n个网站,以及n个网站的关键词,还有一个危险词库.如果一个网站的关键词中>=th的危险词,那么这个网站便是危险的.同时,他的所有关键词加入危险词库.问,有多少个危险网站. ...

  2. poj 2777 线段树的区间更新

    Count Color Time Limit: 1000 MS Memory Limit: 65536 KB 64-bit integer IO format: %I64d , %I64u Java ...

  3. 纯净得只剩下字的访问IP查询API

    纯净得只剩下字的访问IP查询API 实用资源 / 2018-02-26 / 3 条评论 看到一个好玩的,就随手收藏一下,本API作用:获取用户真实IP,而获取用户IP常见的坑有两个,开发支付的时候也需 ...

  4. Linux下可视化空间分析工具ncdu

    场景:磁盘空间占满后快速查找某个目录(子目录)占用空间大. ncdu /var (分析后按左右键查看即可)

  5. 将Azure计算机视觉添加到Xamarin应用程序简单体验

    微软Azure提供了大量的AI及机器学习功能,可以通过简单的RestAPI调用. 关于此文中提到的Azure计算机视觉,可查看此链接的详细介绍. 通过微软的服务,只需要几行代码即可使用计算机视觉中的 ...

  6. WPF学习笔记(1):DataGrid单元格实现逐键过滤功能

    最近,开始学习WPF,其UI设计完全颠覆了传统的设计理念,为程序员提供了极大的自由发挥空间,让我为之惊叹,且为之着迷.然而,WPF在国内的热度却并不高,大部分贴子都是2012年以前的,出版的图书也很少 ...

  7. 背水一战 Windows 10 (41) - 控件(导航类): Frame

    [源码下载] 背水一战 Windows 10 (41) - 控件(导航类): Frame 作者:webabcd 介绍背水一战 Windows 10 之 控件(导航类) Frame 示例Controls ...

  8. ionic3.x angular4.x ng4.x 自定义组件component双向绑定之自定义计数器

    本文主要示例在ionic3.x环境下实现一个自定义计数器,实现后最终效果如图: 1.使用命令创建一个component ionic g component CounterInput 类似的命令还有: ...

  9. 201621123018《Java程序设计》第10周学习报告

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 本次PTA作业题集异常 1. 常用异常 1.1 自己以前编写的代码中经常出现什么异常.需要捕获吗(为 ...

  10. underscore.js源码研究(6)

    概述 很早就想研究underscore源码了,虽然underscore.js这个库有些过时了,但是我还是想学习一下库的架构,函数式编程以及常用方法的编写这些方面的内容,又恰好没什么其它要研究的了,所以 ...