java 通过jni调用linux so动态库
java 通过jni调用linux so动态库
准备
开发
java
C++
总结
java 通过jni调用linux so动态库
欢迎转载 地址:https://blog.csdn.net/qq_15122663/article/details/96732890
最近有个项目需要java调用C++的动态库,所以重温一下操作步骤记录一下。
准备
使用环境intellij idea clion 系统环境centos:
平时开发使用开发环境是windows 所以部署到linux 上面 调试起来比较麻烦
所以开发jni调试还是挺麻烦的,毕竟开发环境和部署环境不一样
1.下载linux版本的jdk,linux上面也要安装jdk环境,不要忘记这一步;
https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
- clion需要环境是MinGW,所有下载一个MinGW;
- linux上面安装 gcc , gcc-c++
- install gcc , gcc-c++ -y
- 把linux版本的jdk里面文件夹include的 jni.h , jawt.h 和 linux文件夹里面的 jni_md.h , jawt_md.h 复制到 MinGW 的include里面,顺便把这4个文件放在 gcc安装文件夹 include里面;
开发
环境配置的差不多了,接下来就是代码部分
首先第一部分就是java代码
java
package com.ruan.jni;
public class Jni {
static { //这个加载绝对路径动态库 System.load("/opt/cpp/com_ruan_jni_Jni.so"); } //实现以下两个原生方法 public native int add(int a , int b); public native String print(String msg);
}
编译将java 生成class文件
之后将class放在linux环境上,将class文件生成需要用到的.h头文件
现在这个class的包名名是 com.ruan.jni
所以在linux的 根目录创建 这3级目录
cd /
mkdir com
cd com
mkdir ruan
cd ruan
mkdir jni
之后将class文件放在/com/ruan/jni文件夹下面
下一步就是javah生成.h头文件
javah -classpath A -d B -jni C
1
A: com/ruan/jni这三级文件夹的目录 我们这里使用的是根目录所以是 /
B:输出文件的目录
C:需要编译的class文件,这个重点就是一定要加上包名 com.ruan.jni.Jni 后面的class后缀不需要
javah -classpath / -d / -jni com.ruan.jni.Jni
1
之后就会在根目录 生成 一个 名称为 com_ruan_jni_Jni.h头文件
/ DO NOT EDIT THIS FILE - it is machine generated /
include
/ Header for class com_ruan_jni_Jni /
ifndef _Included_com_ruan_jni_Jni
define _Included_com_ruan_jni_Jni
ifdef __cplusplus
extern "C" {
endif
/*
- Class: com_ruan_jni_Jni
- Method: add
- Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_ruan_jni_Jni_add
(JNIEnv *, jobject, jint, jint);
/*
- Class: com_ruan_jni_Jni
- Method: print
- Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_ruan_jni_Jni_print
(JNIEnv *, jobject, jstring);
ifdef __cplusplus
}
endif
endif
上面就是生成的头文件
头文件生成之后就是编写实现的cpp文件
第二部分 编写C++代码
C++
cpp文件名称和.h文件名称一样
com_ruan_jni_Jni.cpp
include
include
include
include
using namespace std;
JNIEXPORT jint JNICALL Java_com_ruan_jni_Jni_add(JNIEnv *env, jobject job, jint a, jint b) {
jint c; c = a + b; return c;
}
JNIEXPORT jstring JNICALL Java_com_ruan_jni_Jni_print(JNIEnv *env, jobject job, jstring s){
// const char *buf = env->GetStringUTFChars(s , NULL);
char str[] = "欢迎你的到来!"; //字符串拼接,实现strContent+str1,因为strcat的第一个参数必须为非const类型(可变),所以不能直接使用strcat() //创建一个新的字符串指针
// char strTemp = (char ) malloc(strlen(buf) + strlen(str) + 1);
//拷贝常量到字符串指针
// strcpy(strTemp,buf);
//拼接str1到strTemp
// strcat(strTemp,str);
std::string hello = "Hello from C++"; printf(str); return env->NewStringUTF(hello.c_str());
// return env->NewStringUTF(str);
}
上面代码就是实现原生方法的具体实现方式 紧做参考
现在源码和头文件都有了,接下来就是生成动态库so文件
之后将cpp和.h文件在linux环境生成so文件
g++ -fPIC -shared -o A B
1
A:生成动态库的名称
B:生成动态库需要用到的文件 我们这里使用的 com_ruan_jni_Jni.cpp和com_ruan_jni_Jni.h
g++ -fPIC -shared -o com_ruan_jni_Jni.so com_ruan_jni_Jni*
1
后面之所以加入* 因为要加入多个文件
package com.ruan.jni;
public class Main {
public static void main(String[] args) { System.out.println(new Jni().print("测试打印")); System.out.println(new Jni().add(1 , 2)); }
}
运行上面的方法就可以输出打印
不过唯一注意 这个要打包到linux环境上面进行 运行
java -jar xxx.jar
1
否则会报错
总结
上面就是简单的 java 调用C++方式,这个是居于java jni生成的头文件进行编写的so,
但是如果遇到so不是按照jni生成头文件提供的接口,那么这种方式 显然只是完成一部分而已,还不能直接使用最原生的C/C++动态库,那么最直接的方法,就是在原生的so上面进行封装一层 按照jni格式的 so 让java来调用
这种方法 后续有时间再记录一下,今天到这里
作者:灰太狼Ruan
来源:CSDN
原文:https://blog.csdn.net/qq_15122663/article/details/96732890
版权声明:本文为博主原创文章,转载请附上博文链接!
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Python基于 ImageAI 模块实践 idenprof数据集识别预测分析
Python基于 ImageAI 模块实践 idenprof数据集识别预测分析 图像识别早已不是很新鲜的话题了,很多数据处理的任务到最后都会归为图像识别中,在之前的很多工作中,我陆陆续续也接触了很多相关的工作,从最开始数据处理,到模型搭建与最终上线也都经历,大多数时候模型都是自己搭建的,虽然说现在keras的出现极大地简化了模型的搭建工作,但是整个过程还是需要自己去实践完成的,对于很多的初学者来说并不是很容易的。 今天发现了一个好玩的库——ImageAI,简单的说一下我的理解就是对keras的又一层封装,但又不全是这样。ImageAI简化了整个图像识别和目标检测的工作,今天想来简单看看,整个模块的能力。 使用的使用网上公开的数据集 idenprof ,分为train和test两个数据集,每个集合里面共有10个类别,数据集截图如下: 具体实践如下: !usr/bin/env python encoding:utf-8 from future import division """__Author__:沂水寒城功能: python基于 ImageAI 模块实现 iden...
- 下一篇
JAVA面试题 线程的生命周期包括哪几个阶段?
JAVA面试题 线程的生命周期包括哪几个阶段?面试官:您知道线程的生命周期包括哪几个阶段? 应聘者: 线程的生命周期包含5个阶段,包括:新建、就绪、运行、阻塞、销毁。 新建:就是刚使用new方法,new出来的线程; 就绪:就是调用的线程的start()方法后,这时候线程处于等待CPU分配资源阶段,谁先抢的CPU资源,谁开始执行; 运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run方法定义了线程的操作和功能; 阻塞:在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态,比如sleep()、wait()之后线程就处于了阻塞状态,这个时候需要其他机制将处于阻塞状态的线程唤醒,比如调用notify或者notifyAll()方法。唤醒的线程不会立刻执行run方法,它们要再次等待CPU分配资源进入运行状态; 销毁:如果线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁,释放资源; 完整的生命周期图如下: 新建状态 我们来看下面一段代码: 1Thread t1 = new Thread();这里的创建,仅仅是在JAVA的这种编程语言层面被创...
相关文章
文章评论
共有0条评论来说两句吧...