Java跨语言通信之C语言

标签: Java 分类: Java 创建时间:2019-11-15 02:41:56 更新时间:2024-11-15 10:49:43

前言

java实现跨语言通信,我一直有一个疑问,就是说使用c或者c++,或者是使用python写的模型,如何才能用在java中,或者说,比如有些高级的算法,python删除的科学计算和数据预测,如何通过java传递参数,然后使用python进行数据预测,然后获取预测结果,返回到java中,然后供后台调用呢?这个流程是这样的吗?还是说这个流程本身就不正确的。

1.java调用c程序

参考文章:
1.java JNI(java 调用c语言程序) 我大部分的内容都是跟着这篇文章做的,但是也是有些不正确的地方,也就顺便解决了
2.Java跨语言调用实现方案(转)

1.编写Helloworld.java

创建 com/test 文件夹,编写Helloworld.java文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.test;
public class Helloworld {
private static final String HELLOWORLD = "hello"; // 这是你生成的动态链接库的名字,比如我生成的是 libhello.so,就写 hello
public native String helloword_C(); //由C语言实现

private static Helloworld instance = new Helloworld();

private Helloworld() {
System.loadLibrary(HELLOWORLD); //会load libosid.so
}

public static String helloword() {
return instance.helloword_C();
}
public static void main(String[] args) {
// 调用c方法
// helloword();
// 调用输出
System.out.println(helloword());
}
}

2.编译java文件

进入到com/test文件夹,进行java文件编译

1
2
3
4
5
## 编译java
javac Helloworld.java

## 编译头文件,中间的点不要忘记了
javac -h . Helloworld.java

会生成 com_test_Helloworld.h头文件

3.编写C代码

编写com_test_Helloworld.c,其中的 Java_com_test_Helloworld_helloword_1C 是上一步的.h生成的函数名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "com_test_Helloworld.h"
#include <stdio.h>
#include <string.h>
char encode[128] = {'\0'};

char * helloword_C(){

static char helloStr[20] = "Hello World";

printf("输出内容: %s\n", helloStr );

return helloStr;
}

JNIEXPORT jstring JNICALL Java_com_test_Helloworld_helloword_1C(JNIEnv * env, jobject obj){
return (*env)->NewStringUTF(env, helloword_C());
}

void main()
{
printf("%s", helloword_C());
}

4.配置C/C++开发环境

我的开发环境是Deepin,使用了VScode进行代码编辑,为了不让开发环境报错,我进行了这一步操作。

(1) 安装完C/C++插件

(2) Ctrl+Shift+P,打开命令行,输入 C/C++,打开编辑配置

(3) 关闭重启VScode

(4)打开.vscode文件夹下的c_cpp_properties.json文件,配置includePath路径,指向JAVA_HOME的include和include/linux

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${JAVA_HOME}/include",
"${JAVA_HOME}/include/linux"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64"
}
],
"version": 4
}

这样就不会报找不到 jni.h 文件的错误了。


如果想要使用VScode进行调试,还需要下面的步骤

(5) 生成启动文件

Ctrl+Shift+P -> Tasks: Configure Tasks… -> Create tasks.json file from templates -> Others.

5.编译c

如果直接使用gcc进行编译的话,可能会遇到找不到 jni.h 文件的问题,需要添加 gcc 的 includepath 目录,如下增加环境变量

1
2
3
4
5
6
## 增加环境变量
export C_INCLUDE_PATH=$JAVA_HOME/include:$JAVA_HOME/include/linux:$C_INCLUDE_PATH
## 执行编译
gcc -fPIC -shared -c com_test_Helloworld.c
## 打包为.so动态链接库,一定要以lib开头
gcc -fPIC -shared com_test_Helloworld.o -o libhello.so
参考文章:
1.修改gcc/g++默认include路径 除了默认的/usr/include, /usr/local/include等include路径外,还可以通过设置环境变量来添加系统include的路径 :export C_INCLUDE_PATH=XXXX:$C_INCLUDE_PATH

6.复制文件

将生成的.so文件放到 $JAVA_HOME/jre/lib/amd64 目录下,如果没有这个目录,那就直接放到 $JAVA_HOME/lib目录下也可以。

7.运行java程序

在com/test目录下,运行java文件,就可以了。

1
java Helloworld.java

可以看到,已经有结果了。

Exception in thread “main” java.lang.UnsatisfiedLinkError

这个问题我是重新进行了上面的几步操作才解决了问题,因为我在其中改变了部分的代码原因吧。

参考文章:
1.Java中调用c/c++语言出现Exception in thread “main” java.lang.UnsatisfiedLinkError: Test.testPrint(Ljava/lang/String;)V…错误
2.Exception in thread “main” java.lang.UnsatisfiedLinkError”
3.java.lang.UnsatisfiedLinkError解决方法汇集 这里还提到了其他的错误,比如:Java.lang.System.loadLibrary(System.java:834) 分析: 这种错误在我们使用热启动方式发布某个使用了JNI技术的Web应用时,并将调用年native方法的jar包独立部署在该应用下面,当我们的Web应用有了更新以后,在调用到该jar包封装的native方法时,会抛出该错误。(以上OS为Windows,若是Linux或Unix,应该是xxx.so报错) 这是因为Web服务器已经在第一次加载该应用时,已经load了该dll,当该应用被再次热启动时,该dll将重新被加载,于是报错。 解决方案: 一、将含有JNI调用的jar包部署在Web服务器的公用lib库中。Web应用再发布时可以不用加载; 二、jar包部署不变,在该Web中实现一个listener,监听是否第一次启动,若不是第一次启动,屏蔽掉该jar包所含dll的加载。
小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。