背景
最近由于工作需求,让CC++老狗用Java完成项目的一个大功能,其中涉及到用Java调用CC++版本的SDK的问题。因此,研究了一下JNI、JNA这些东西是何物,然后再做些验证。
调用过程
JNI
JNI(Java Native Interface)即Java本地接口。它提供了若干API来实现Java和其他语言的通信,主要是C&C++。其调用过程如下:
- 编写Java类代码(*.java)
- 编译生成字节码(*.class)
- 生成C&C++头文件(*.h)
- 编写JNI实现代码(*.c/*.cpp)
- 编译生成链接库(*.dll/*.so)
- 运行含链接库文件的Java程序
使用JNI技术来调用动态库,得完成第四步中的程序实现,这对Java阵营的程序员不太友好。
JNA
JNA(Java Native Access ),即Java本地访问。它提供一组Java工具类用于在运行期间动态访问系统本地库而不需要编写任何Native/JNI代码。开发人员只要在一个Java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射。
其调过程用如下:
- 编写JNA实现代码(*.java)(Java对应C&C++库的接口映射文件)
- 编程陈字节码(*.class)
- 运行含链接库文件的Java程序
从上面可以看出,使用JNA技术调用Linux动态库相对简化很多,在这里只需要一个JNA的jar包和懂得JAVA的编程知识即可。
验证过程
开发环境
环境名称 | 内容 |
Linux系统 | Linux localhost.localdomain 4.18.0-193.el8.x86_64 #1 SMP Fri May 8 10:59:10 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux |
Java | openjdk version "1.8.0_302" OpenJDK Runtime Environment (build 1.8.0_302-b08) OpenJDK 64-Bit Server VM (build 25.302-b08, mixed mode) |
JNA | jna-4.2.2.jar |
代码结构
C/C++
树形图
代码内容
SayHello.h
#ifndef HELLOSO_SAYHELLO_H
#define HELLOSO_SAYHELLO_H
extern "C"
{
int SayHello();
int Add(int a, int b);
char* OutputString(char* str);
}
#endif
SayHello.cc
#include "SayHello.h"
#include <iostream>
int SayHello()
{
std::cout<<"Hello"<<std::endl;
return 1;
}
int Add(int a, int b)
{
return a + b;
}
char* OutputString(char* ch)
{
return ch;
}
CMakeLists.txt
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (sayhello)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
add_library(${PROJECT_NAME} SHARED ${DIR_SRCS})
#设置动态库属性、版本等
#set_target_properties(${PROJECT_NAME} PROPERTIES VERSION 1.0.0 SOVERSION 1)
JAVA
树形结构
代码类容
CLibrary.java
import com.sun.jna.Library;
import com.sun.jna.Native;
public interface CLibrary extends Library{
CLibrary INSTANCE = (CLibrary)Native.loadLibrary("sayhello", CLibrary.class);
// c function name
int SayHello();
int Add(int a, int b);
String OutputString(String str);
}
JNATest.java
public class JNATest{
public static void main(String[] args) {
int result = CLibrary.INSTANCE.SayHello();
int a = 3;
int b = 5;
System.out.println("a+b= " + CLibrary.INSTANCE.Add(a, b));
System.out.println("outputString:" + CLibrary.INSTANCE.OutputString("Huahaoyueeryuan!"));
}
}
注意事项
- CC++函数实现时需要将函数编译成C格式的,即在函数声明出加extern “C”,否则会出现undefined symbol报错。这里有个小问题,这样就不支持函数重载。
- CLibrary.java加载动态的路径默认为LD_LIBRARY_PATH,当LD_LIBRARY_PATH未指定时需要明确指出libsayhello.so文件的位置。 参考命令:export LD_LIBRARY_PATH=/home/javaessay/JNATest/src/main/resources/
- CLibrary.java中即JNA实现CC++接口映射关系时,函数名称需与CC++函数名保持一致。
- 编译java文件时,需要指定jna包路径。一般在CLASSPATH后添加,否则需明确指出jar位置。参考命令:javac -cp :/home/jna-4.2.2.jar *.java
- 执行java文件时,需要指定jna包路径。一般在CLASSPATH后添加,否则需明确指出jar位置。参考命令:java -cp :/home/jna-4.2.2.jar JNATest
- Java中变量类型必须与C中一一对应。Java变量类型与C变量类型对应关系见附属表。
至此,Linux下JAVA程序调用动态库的接口函数实例编写完成并执行成功。
总结
就酱。
其他
Java、C和操作系统数据类型的对应表
Java类型 | C系类型 | 本地类型 |
boolean | int | 32-bit integer |
byte | char | 8-bit integer |
char | wchar_t | platform dependent |
short | short | 16-bit integer |
int | int | 32-bit integer |
long | long long, __int64 | 64-bit integer |
float | float | 32-bit float pointer |
double | double | 64-bit float pointer |
Buffer/Pointer | pointer | 32-bit or 64-bit pointer to memory |
<T>[] | pointer array | 32-bit or 64-bit pointer to memory (argument/return) contiguous memory (struct member |
String | char* | NUL-terminated array |
WString | wchar_t* | NUL-terminated array |
String[] | char** | NUL-terminated array of C strings |
WString[] | wchar_t** | NUL-terminated array of wide C strings |
Structure | struct * struct | pointer to struct (argument or return) (or explicitly) struct by value (member of struct) (or explicitly) |
Union | union | pointer to struct (argument or return) (or explicitly) struct by value (member of struct) (or explicitly) |
Structure[] | struct[] | array of structs, contiguous in memory |
Callback | <T>(*fp)() | function pointer |
NativeMapped | varies | depends on definitions |
NativeLong | long | 32-bit or 64-bit integer |
PointerType | pointer | 32-bit or 64-bit pointer to memory |