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
相关推荐
浮游本尊13 分钟前
Java学习第22天 - 云原生与容器化
java
渣哥2 小时前
原来 Java 里线程安全集合有这么多种
java
间彧2 小时前
Spring Boot集成Spring Security完整指南
java
间彧3 小时前
Spring Secutiy基本原理及工作流程
java
Java水解4 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
洛小豆6 小时前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试
前端小张同学6 小时前
服务器上如何搭建jenkins 服务CI/CD😎😎
java·后端
ytadpole6 小时前
Spring Cloud Gateway:一次不规范 URL 引发的路由转发404问题排查
java·后端
华仔啊6 小时前
基于 RuoYi-Vue 轻松实现单用户登录功能,亲测有效
java·vue.js·后端