java 通过jni调用linux so动态库

简介: java 通过jni调用linux so动态库准备开发javaC++总结java 通过jni调用linux so动态库欢迎转载 地址:https://blog.csdn.net/qq_15122663/article/details/96732890最近有个项目需要java调用C++的动态库,所以重温一下操作步骤记录一下。

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

  1. clion需要环境是MinGW,所有下载一个MinGW;
  2. linux上面安装 gcc , gcc-c++
  3. install gcc , gcc-c++ -y
  4. 把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
版权声明:本文为博主原创文章,转载请附上博文链接!

相关文章
|
5月前
|
安全 Linux vr&ar
Linux的动态库和静态库
Linux的动态库和静态库
|
2月前
|
分布式计算 Java Hadoop
linux中HADOOP_HOME和JAVA_HOME删除后依然指向旧目录
通过以上步骤,可以有效地解决 `HADOOP_HOME`和 `JAVA_HOME`删除后依然指向旧目录的问题。确保在所有相关的配置文件中正确设置和删除环境变量,并刷新当前会话,使更改生效。通过这些措施,能够确保系统环境变量的正确性和一致性。
31 1
|
3月前
|
运维 Java Linux
【运维基础知识】Linux服务器下手写启停Java程序脚本start.sh stop.sh及详细说明
### 启动Java程序脚本 `start.sh` 此脚本用于启动一个Java程序,设置JVM字符集为GBK,最大堆内存为3000M,并将程序的日志输出到`output.log`文件中,同时在后台运行。 ### 停止Java程序脚本 `stop.sh` 此脚本用于停止指定名称的服务(如`QuoteServer`),通过查找并终止该服务的Java进程,输出操作结果以确认是否成功。
87 1
|
4月前
|
消息中间件 分布式计算 Java
Linux环境下 java程序提交spark任务到Yarn报错
Linux环境下 java程序提交spark任务到Yarn报错
54 5
|
4月前
|
Java Linux Python
Linux环境下 代码java调用python出错
Linux环境下 代码java调用python出错
74 4
|
4月前
|
Oracle Java 关系型数据库
Linux下JDK环境的配置及 bash: /usr/local/java/bin/java: cannot execute binary file: exec format error问题的解决
如果遇到"exec format error"问题,文章建议先检查Linux操作系统是32位还是64位,并确保安装了与系统匹配的JDK版本。如果系统是64位的,但出现了错误,可能是因为下载了错误的JDK版本。文章提供了一个链接,指向Oracle官网上的JDK 17 Linux版本下载页面,并附有截图说明。
Linux下JDK环境的配置及 bash: /usr/local/java/bin/java: cannot execute binary file: exec format error问题的解决
|
4月前
|
安全 Java API
【性能与安全的双重飞跃】JDK 22外部函数与内存API:JNI的继任者,引领Java新潮流!
【9月更文挑战第7天】JDK 22外部函数与内存API的发布,标志着Java在性能与安全性方面实现了双重飞跃。作为JNI的继任者,这一新特性不仅简化了Java与本地代码的交互过程,还提升了程序的性能和安全性。我们有理由相信,在外部函数与内存API的引领下,Java将开启一个全新的编程时代,为开发者们带来更加高效、更加安全的编程体验。让我们共同期待Java在未来的辉煌成就!
81 11
|
4月前
|
安全 Java API
【本地与Java无缝对接】JDK 22外部函数和内存API:JNI终结者,性能与安全双提升!
【9月更文挑战第6天】JDK 22的外部函数和内存API无疑是Java编程语言发展史上的一个重要里程碑。它不仅解决了JNI的诸多局限和挑战,还为Java与本地代码的互操作提供了更加高效、安全和简洁的解决方案。随着FFM API的逐渐成熟和完善,我们有理由相信,Java将在更多领域展现出其强大的生命力和竞争力。让我们共同期待Java编程新纪元的到来!
126 11
|
3月前
|
Java Linux Maven
用sdkman在linux上管理多个java版本
本文介绍了如何在Linux上使用SDKMAN来管理多个Java版本,包括安装SDKMAN、验证安装、列出和安装不同版本的JDK、Maven和Gradle,以及如何切换使用不同版本。
87 0
|
5月前
|
开发框架 Java Android开发
JNI中调用Java函数
JNI中调用Java函数
35 0