JAVA JNA调用Linux动态库指南

背景

最近由于工作需求,让CC++老狗用Java完成项目的一个大功能,其中涉及到用Java调用CC++版本的SDK的问题。因此,研究了一下JNI、JNA这些东西是何物,然后再做些验证。

调用过程

JNI

JNI(Java Native Interface)即Java本地接口。它提供了若干API来实现Java和其他语言的通信,主要是C&C++。其调用过程如下:

  1. 编写Java类代码(*.java)
  2. 编译生成字节码(*.class)
  3. 生成C&C++头文件(*.h)
  4. 编写JNI实现代码(*.c/*.cpp)
  5. 编译生成链接库(*.dll/*.so)
  6. 运行含链接库文件的Java程序

使用JNI技术来调用动态库,得完成第四步中的程序实现,这对Java阵营的程序员不太友好。

JNA

JNA(Java Native Access ),即Java本地访问。它提供一组Java工具类用于在运行期间动态访问系统本地库而不需要编写任何Native/JNI代码。开发人员只要在一个Java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射。

其调过程用如下:

  1. 编写JNA实现代码(*.java)(Java对应C&C++库的接口映射文件)
  2. 编程陈字节码(*.class)
  3. 运行含链接库文件的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!"));
    }
}

注意事项

  1. CC++函数实现时需要将函数编译成C格式的,即在函数声明出加extern “C”,否则会出现undefined symbol报错。这里有个小问题,这样就不支持函数重载。
  2. CLibrary.java加载动态的路径默认为LD_LIBRARY_PATH,当LD_LIBRARY_PATH未指定时需要明确指出libsayhello.so文件的位置。                                                                              参考命令:export LD_LIBRARY_PATH=/home/javaessay/JNATest/src/main/resources/
  3. CLibrary.java中即JNA实现CC++接口映射关系时,函数名称需与CC++函数名保持一致。
  4. 编译java文件时,需要指定jna包路径。一般在CLASSPATH后添加,否则需明确指出jar位置。参考命令:javac -cp :/home/jna-4.2.2.jar *.java
  5. 执行java文件时,需要指定jna包路径。一般在CLASSPATH后添加,否则需明确指出jar位置。参考命令:java -cp :/home/jna-4.2.2.jar JNATest
  6. 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

参考资料

Linux下JAVA程序调用so库的接口函数实例(JNA)_这世上所有的久处不厌,都是因为用心-CSDN博客

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值