本文是JNI专题的开头文章,主要介绍JNI项目如何从零到整的过程

一、JNI简介

Java Native Interface,即Java本地接口。
它允许在Java虚拟机内运行的java代码与其他编程语言(如c, c++和汇编语言)编写的程序和库进行交互。简单点说, JNI可以帮助我们用java代码访问其他编程语言

二、JNI项目

需求:开发 JAVA WEB服务调用已有的so动态链接库,完成相关的业务功能开发。
因此需要借助JNI技术来完成。标准JNI的结构如下

java代码借助JNI调用由C代码生成的动态链接库文件(SO文件),从而访问C程序的函数,最后得到函数执行的结果。
但是这套东西要求C语言的函数命名要符合JNI的规则才能被JAVA识别。所以经过分析与预研,最后的结构变成

引入自定义的C编程,以及自定义的标准动态链接库。然后再用自定义的C去调用外部的非标准C程序。
因此,项目的JNI编程既包括java程序的开发,还包括C语言程序的开发。

技术要点:

1、JNI编程相关
2、C语言调用动态链接库
3、动态链接库生成

三、JNI编程

JNI编程目的:JAVA调用C的动态链接库函数
JNI例子的目标:调用Cadd方法完成两数相加计算,返回结果;打印一串子串并返回

1、编写JAVA程序

/*** HelloJNI*/
public class HelloJNI {static {// 加载动态链接库System.load("/program/jni/libHelloJNI.so");}/*** 声明两个Native Method,对应C的两个方法*/public static native int add(int a, int b);public static native void hello();public static void main(String[] args) {// 调用 add方法,完成计算int sum = add(5, 6);System.out.println("sum=" + sum);// 调用 hello方法,在c语言内完成打印hello();}
}

说明:
Native Method就是一个java调用非java代码的接口,该方法的实现由非java语言实现,比如C。也就是说java只写接口代码,不写实现。实现在C程序

2、编译java
①上传HelloJNI.java到linux环境的/program/jni目录
②执行命令编译

javac -encoding utf-8  HelloJNI.java

③执行命令生成JNI头文件文件

javah -jni HelloJNI

说明:
(1)必须先编译完java才能执行,因为是建立在.class文件之上
(2)命令中HelloJNI表示类名,如果该类有package,要加上完整的包名,然后javah 命令一定要在包路径的上层。比如 HelloJNI的完整类名是com.test.jni.HelloJNI,那么HelloJNI.class文件需要放在
/program/jni/com/test/jni目录下,然后到/program/jni目录执行命令javah -jni HelloJNI
(3)现在的例子没有package,执行完,现在目录有三个文件

3、开发c
首先我们拿到上面生成的HelloJNI.h文件,里面的内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloJNI */#ifndef _Included_HelloJNI
#define _Included_HelloJNI
#ifdef __cplusplus
extern "C" {#endif
/** Class:     HelloJNI* Method:    add* Signature: (II)I*/
JNIEXPORT jint JNICALL Java_HelloJNI_add(JNIEnv *, jclass, jint, jint);/** Class:     HelloJNI* Method:    hello* Signature: ()V*/
JNIEXPORT void JNICALL Java_HelloJNI_hello(JNIEnv *, jclass);#ifdef __cplusplus
}
#endif
#endif

新建HelloJNI.c,内容如下

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include "HelloJNI.h"/** Class:     HelloJNI* Method:    add* Signature: (II)I*/
JNIEXPORT jint JNICALL Java_HelloJNI_add(JNIEnv *env, jclass jc, jint a, jint b){return a + b;
}/** Class:     HelloJNI* Method:    hello* Signature: ()Ljava/lang/String;*/
JNIEXPORT void JNICALL Java_HelloJNI_hello (JNIEnv *env, jclass jc){printf("%s\n", "hello world!");
}

说明:
①加上#include “HelloJNI.h”,就是把之前生成的头文件引入
②在HelloJNI.h的基础上写上函数体
③需要去掉HelloJNI.h多余的注解,然后补全函数变量和函数体

4、编译C文件
在/program/jni目录下执行命令

gcc -fPIC -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -shared -o libHelloJNI.so HelloJNI.c

至此,目录/program/jni下的文件有

5、运行程序
在/program/jni目录下执行命令

java HelloJNI

运行结果如下,符合预期

6、命令汇总
编译java: javac HelloJNI.java
生成Native Method函数映射头文件: javah -jni HelloJNI
生成c文件的动态链接库: gcc -fPIC -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -shared -o libHelloJNI.so HelloJNI.c
运行java程序: java HelloJNI

至此,已经完成标准JNI的整个开发
即完成 HelloJNI.java–>HelloJNI.c的部分开发与验证

四、非标准SO调用

目标:实现HelloJNI.java–>HelloJNI.c–>hello.c的开发与验证
其中hello.c是非标准JNI的C程序
回过头看看什么事标准JNI的C程序,有配套的头文件HelloJNI.h,并且就是函数命名如

JNIEXPORT jint JNICALL Java_HelloJNI_add(JNIEnv *env, jclass jc, jint a, jint b)

简单扥说 JNIEXPORT jint JNICALL 形式表示java native映射并调用的声明,JNIEnv ,jclass ,jint 等是JNI的变量类型,基本类型对应如下,更多的对应可以去=去网上查

现在有非JNI标准c程序hello.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>/*** 返回a+b的值*/
int add(int a, int b){return a + b;
}

现在的需求就变成我们要用java调用这个函数,下面开始!

1、生成hello.c的so
将hello.c放到/program/jni目录,在该目录下执行命令

gcc -fPIC -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -shared -o libhello.so hello.c

此时会生成文件libhello.so

2、标准c开发
我们把之前的HelloJNI.c进行改造

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include "dlfcn.h"
#include "HelloJNI.h"/** Class:     HelloJNI* Method:    add* Signature: (II)I*/
JNIEXPORT jint JNICALL Java_HelloJNI_add(JNIEnv *env, jclass jc, jint a, jint b){// 加载连接库void *handle = dlopen("/program/jni/libhello.so", RTLD_LAZY);if (handle == NULL) {return -1;}// 定义调用的函数int (*doFunc)(int , int) = NULL;// 声明执行函数doFunc = (int (*)(int, int)) dlsym(handle, "add");// 执行调用int result = doFunc(a, b);}/** Class:     HelloJNI* Method:    hello* Signature: ()Ljava/lang/String;*/
JNIEXPORT void JNICALL Java_HelloJNI_hello (JNIEnv *env, jclass jc){printf("%s\n", "hello world!");
}

说明:
①引入 #include “dlfcn.h” 因为底下加载外部链接库用到一些关键字
②用dlopen加载非标准的动态链接库

3、运行程序
因为其他的文件用之前的,没变,所以只需要执行

gcc -fPIC -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -shared -o libHelloJNI.so HelloJNI.c;
java HelloJNI;

运行结果

最终的文件列表如下

五、总结

至此,完成了整个调用链,整个文章,最终追求的效果如下

.
.
.
.
.下 一 篇.:JNI对象传参与返回对象结果-C结构体参数【二】

JNI入门与进阶,JNI调用外部非标准程序SO【一】相关推荐

  1. java main方法调用非静态方法_java中main函数怎么调用外部非static方法

    展开全部 方法可以分为静态方法和实例方法 在main函数里调用非static方法(实例方法),那么32313133353236313431303231363533e78988e69d833133336 ...

  2. JNI入门课程-第二章:JNI基础调用

    序章: 1.本篇是JNI入门教程的第二篇,偏基础功能的实现.完整教程连接如下: https://blog.csdn.net/rzleilei/article/details/122084609http ...

  3. 史上最详细的JNI入门教程HelloNative

    为什么80%的码农都做不了架构师?>>>    欢迎点击「算法与编程之美」↑关注我们! 本文首发于微信公众号:"算法与编程之美",欢迎关注. 1 为什么写本文 互 ...

  4. Android JNI(二)——实战JNI入门之Hello World

    上一篇我们讲解了ndk以及jni基础,接下来以实战方式讲解几种常见的jni调用方式,带你走进jni世界. 大纲 今天会详细讲解几种jni的实现方式,实战NDK实现 "hello world& ...

  5. JNI入门学程之HelloWorld篇

    如果你对Jni不甚懂得,不晓得Jni是作什么的,如何树立一个基础的jni程序,或允许以参考下面下面这些文章: 应用VC++6.0实现JNI的最简单的例子 JNI入门学程之HelloWorld篇 SUN ...

  6. 【翻译】WF从入门到精通(第八章):调用外部方法及工作流

    上一篇:[翻译]WF从入门到精通(第七章):基本活动的操作例 学习完本章,你将掌握:     1.创建并调用你的工作流外部的本地数据服务     2.理解怎样使用接口来为宿主进程和你的工作流之间进行通 ...

  7. ubuntu下的android JNI入门DEMO

    在网上找的jni demo在对着练习的时候,总是多多少少报错. 所以把自己的摸索记录下来 环境: Ubuntu 10.04 LTS eclipse: http://developer.android. ...

  8. VR 终极选购指南:入门、进阶与高端

    若你重回上世纪 90 年代读读 VR,你会发现这个词意涵颇广:从电影<天才割草人>的虚拟空间刺激系统,到电脑屏幕上的3D模型,什么都有.然而发展到今天,VR 简单明了:除某些特定情况,它等 ...

  9. Vue3+TypeScript从入门到进阶(六)——TypeScript知识点——附沿途学习案例及项目实战代码

    文章目录 一.简介 二.Vue2和Vue3区别 三.Vue知识点学习 四.TypeScript知识点 一.JavaScript和TypeScript 二.TypeScript的安装和使用 1.Type ...

  10. python入门与进阶

    title: python入门与进阶 categories: python tags: [python] python入门导学 python的特点 是面向对象的编程语言 简介,灵活,优雅,哲学 易于上 ...

最新文章

  1. java Opencv 图片修复 Photo
  2. koa2入门(3)mongoose 增删改查
  3. linux shc shell脚本_详解shell脚本加密解密软件—gzese和shc
  4. python教程初级有什么用_学Python编程有什么用?Python基础教程!
  5. Spring(二十二):Spring 事务
  6. 远程连接Linux系统
  7. SQL Server数据库复制
  8. WIN10如何管理开机启动项?
  9. java后端AppV3版本微信支付CV大法2021-11-12
  10. 没想到,快手成了“生产力”
  11. 在css文件中字体加粗属性是,css样式表中字体加粗的属性是什么?
  12. gentoo适合做服务器系统吗,Mandriva、Gentoo发行版
  13. Scala历史版本在哪里??
  14. win10无限重启_系统更新后无限重启怎么办?
  15. UVM学习笔记--sequence和sequencer
  16. AndroidStudio 跑马灯效果不自动滚动的原因
  17. 阿里云服务部署webcron定时服务管理系统
  18. D7100 调节白平衡
  19. c语言漂亮的壁纸编码,怎么用c语言写一个设定壁纸的demo?
  20. Vim7.4 配置项列表

热门文章

  1. 搭建docker监控平台
  2. linux设备驱动之 i2c设备驱动 at24c08驱动程序分析【全部地址的操作】
  3. 十张图看懂华为IPD和LTC
  4. dh算法 理论依据_DH算法
  5. 关于PLC的输入输出点,源型漏型的判断
  6. 延时等待的gcode
  7. 一 破解windows7系统密码
  8. 如何在cad中模块计算机,cad中家具模板哪里找(怎么在CAD图纸里面加入家具)
  9. pygame教程:第一课 初始化和主循环
  10. 峰值信噪比公式_关于 PSNR (Peak Signal-to-Noise Ratio) 峰值信噪比的个人理解