JAVA JNA 调用C接口的三种方式

文章目录

  • [1. 准备一个共享库文件](#1. 准备一个共享库文件)
  • [2. JNA姿势1---继承Library接口](#2. JNA姿势1—继承Library接口)
  • [3. JNA姿势2---直接NativeLibrary.getInstance](#3. JNA姿势2—直接NativeLibrary.getInstance)
  • [3. JNA姿势3---Native方法](#3. JNA姿势3—Native方法)

1. 准备一个共享库文件

test.c

c 复制代码
#include <stdio.h>
int test(char *input){
    printf("input:%s\n",input);
    return 0;
}

libtest.so

sh 复制代码
[root@node-126 ~]# gcc -fPIC -shared -o libtest.so test.c 
[root@node-126 ~]# ls /root/
anaconda-ks.cfg  libtest.so  node-v6.10.2-linux-x64.tar.xz  original-ks.cfg  spring3  test  test.c

可以看到有test方法

sh 复制代码
[root@node-126 ~]# nm -D libtest.so 
0000000000201038 B __bss_start
                 w __cxa_finalize
0000000000201038 D _edata
0000000000201040 B _end
0000000000000600 T _fini
                 w __gmon_start__
00000000000004c0 T _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U printf
00000000000005d5 T test

2. JNA姿势1---继承Library接口

建个普通maven项目

pom 复制代码
       <dependency>
            <groupId>net.java.dev.jna</groupId>
            <artifactId>jna</artifactId>
            <version>5.5.0</version>
        </dependency>
java 复制代码
package jna;

import com.sun.jna.Library;
import com.sun.jna.Native;

/**
 * 接口继承
 *
 * @author majun
 * @version 1.0
 * @since 2023-08-22 22:27
 */
public interface MyClibrary extends Library {
    MyClibrary INSTANTCE = Native.load("/root/libtest.so", MyClibrary.class);
    int test(String input);
}

测试

java 复制代码
import jna.MyClibrary;

/**
 * TODO
 *
 * @author majun
 * @version 1.0
 * @since 2023-03-31 7:44
 */
public class Main {
    public static void main(String[] args) {
        int test = MyClibrary.INSTANTCE.test("extend Library");
        System.out.println(test);
    }
}

使用Linux上的Java运行

3. JNA姿势2---直接NativeLibrary.getInstance

java 复制代码
import com.sun.jna.Function;
import com.sun.jna.NativeLibrary;

/**
 * TODO
 *
 * @author majun
 * @version 1.0
 * @since 2023-03-31 7:44
 */
public class Main {
    public static void main(String[] args) {
        NativeLibrary instance = NativeLibrary.getInstance("/root/libtest.so");
        Function func = instance.getFunction("test");
        Object res = func.invoke(Integer.class, new Object[]{"NativeLibrary.getInstance"});
        System.out.println( res);
    }
}

3. JNA姿势3---Native方法

mkdir -p /root/jna && cd /root/jna 新建MyNative.java

java 复制代码
package jna;
import java.io.IOException;

public class MyNative {
     native int  test(String input) throws IOException;
}

编译并生成头文件(这里java17没找到javah命令,改用java8的,但注意javac ,javah要使用同一个Java版本的)

sh 复制代码
 /usr/local/jdk1.8.0_111/bin/javac  MyNative.java
 /usr/local/jdk1.8.0_111/bin/javah -classpath /root/ -jni   jna.MyNative

linux直接编辑实现头文件中的接口:

c 复制代码
#include <stdio.h>
#include <jni.h>
#include "jna_MyNative.h"
jint  Java_jna_MyNative_test(JNIEnv *jniEnv, jobject clazz, jstring input){
    printf("input:%s\n",(char *)input);
    return 0;
}

编译时注意引入jdk头文件包下的jni.h等

gcc -fPIC -shared -I/usr/lib/jvm/jdk-17-oracle-x64/include -I/usr/lib/jvm/jdk-17-oracle-x64/include/linux -o libtest.so test.c

使用Clion实现头文件的接口:新建C项目,引入jna_MyNative.h,并实现其中的方法

注意

1.使用远程toolchain,cmake编译安装运行,注意cmake版本可能导致include_directories(SYSTEM "/usr/lib/jvm/jdk-17-oracle-x64/include") 同步Linux上jdk的头文件失败,本地无法找到符号,但可以正常运行。

2.jniEnv必须Java调用才会有值。

cmake 复制代码
cmake_minimum_required(VERSION 2.8)
project(untitled1)

set(CMAKE_CXX_STANDARD 17)
include_directories(SYSTEM "/usr/lib/jvm/jdk-17-oracle-x64/include")
include_directories(SYSTEM "/usr/lib/jvm/jdk-17-oracle-x64/include/linux")

add_executable(testexe main.cpp)
add_library(test SHARED main.cpp jna_MyNative.h)
target_link_libraries(test -I/usr/lib/jvm/jdk-17-oracle-x64/include -I/usr/lib/jvm/jdk-17-oracle-x64/linux)
install(TARGETS test LIBRARY DESTINATION /usr/lib)

Java调用测试

java 复制代码
import jna.MyNative;

import java.io.IOException;

/**
 * TODO
 *
 * @author majun
 * @version 1.0
 * @since 2023-08-23 23:44
 */
public class Main {
    public static void main(String[] args) throws IOException {
        System.load("/root/jna/libtest.so");
        //System.loadLibrary("test");// 自动拼接成libtest.so,默认从/usr/lib,/usr/lib64等路径找
        MyNative myNative = new MyNative();
        int test = myNative.test("native");
        System.out.println(test);
    }
}

姿势3实现的C接口,Java依旧可以使用姿势1,2的方式来调用,注意函数名为Java_jna_MyNative_test

sh 复制代码
[root@node-126 lib]# nm -D /usr/lib/libtest.so 
0000000000201070 B __bss_start
                 U __cxa_allocate_exception
                 w __cxa_finalize
                 U __cxa_free_exception
                 U __cxa_throw
0000000000201070 D _edata
0000000000201078 B _end
0000000000000b4c T _fini
                 w __gmon_start__
                 U __gxx_personality_v0
0000000000000860 T _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
0000000000000a15 T Java_jna_MyNative_test
                 w _Jv_RegisterClasses
0000000000000ac8 T main
                 U printf
                 U _Unwind_Resume
0000000000000b18 W _ZN7JNIEnv_8ThrowNewEP7_jclassPKc
0000000000000aea W _ZN7JNIEnv_9FindClassEPKc
                 U _ZTIi
相关推荐
南宫生14 分钟前
力扣-位运算-1【算法学习day.41】
java·学习·算法·leetcode
极客先躯21 分钟前
高级java每日一道面试题-2024年11月22日-JVM篇-说说堆和栈的区别?
java·jvm··
2401_857439691 小时前
企业OA管理系统:Spring Boot技术应用与优化
java·spring boot·后端
2401_857439691 小时前
Spring Boot OA:构建企业级办公自动化平台
java·spring boot·后端
明月*清风1 小时前
【数据结构专栏】二叉搜索树(Binary Search Tree)的剖析?
开发语言·数据结构·c++·visualstudio
qiaoqiaohonghu1 小时前
c/c++ 用easyx图形库写一个射击游戏
c语言·c++·游戏
paterWang1 小时前
小程序-基于java+SpringBoot+Vue的农场管理系统设计与实现
java·spring boot·小程序
尘浮生2 小时前
Java项目实战II基于Java+Spring Boot+MySQL的共享汽车管理系统(源码+数据库+文档)
java·数据库·spring boot·mysql·微信小程序·小程序·汽车
雪碧聊技术2 小时前
RabbitMQ3:Java客户端快速入门
java·开发语言·rabbitmq·amqp·spring amqp·rabbittemplate
Sinsa_SI2 小时前
2024年9月中国电子学会青少年软件编程(Python)等级考试试卷(六级)答案 + 解析
开发语言·python·等级考试·电子学会·考级