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

这篇具有很好参考价值的文章主要介绍了JAVA JNA 调用C接口的三种方式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 准备一个共享库文件

test.c

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

libtest.so

[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方法

[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项目

       <dependency>
            <groupId>net.java.dev.jna</groupId>
            <artifactId>jna</artifactId>
            <version>5.5.0</version>
        </dependency>
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);
}

测试

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运行
JAVA JNA 调用C接口的三种方式,java,c语言,开发语言

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

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


package jna;
import java.io.IOException;

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

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

 /usr/local/jdk1.8.0_111/bin/javac  MyNative.java
 /usr/local/jdk1.8.0_111/bin/javah -classpath /root/ -jni   jna.MyNative

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

#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,并实现其中的方法

JAVA JNA 调用C接口的三种方式,java,c语言,开发语言

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

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调用测试

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文章来源地址https://www.toymoban.com/news/detail-680401.html

[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

到了这里,关于JAVA JNA 调用C接口的三种方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • Java创建数组的三种方式

    这种一般用的比较多。 数组类型 [ ]  数组名称  =  new 数组类型 [ 数组长度 ] 

    2024年02月03日
    浏览(13)
  • Java数组的三种声明方式

    1.在开发中为什么要使用数组 如果开发中出现了大量的同一个类型的数据,按照现在所学的知识点,声明变量的话。如果一个变量存一个数据的话,那么就会需要多个变量了,相当麻烦。 使用数组: 只需要一个变量,然后数组中存很多的数据, 其实可以把数组想成 一个容器

    2024年02月05日
    浏览(12)
  • Java 多线程实现的三种方式

    Java 多线程实现方式主要有三种:继承 Thread 类、实现 Runnable 接口、使用 ExecutorService、Callable、Future 实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。 1、继承 Thread 类实现多线程 继承 Thread 类的方法尽管被我列为一种多线程

    2023年04月27日
    浏览(12)
  • Java 实现多线程的三种方式

    1、三种方法的介绍和比较 1、1三种方式得介绍 1、继承Thread类 2、实现Runnable接口 3、实现Callable接口 1、2三种方法的介绍和比较 1、2、1、实现Runnable接口相比继承Thread类有如下优势 1、增强程序的健壮性,将业务逻辑与线程调度分离 2、线程池只能放入实现Runable或Callable类线程

    2024年02月02日
    浏览(11)
  • Java多线程 - 创建的三种方式介绍

    什么是线程 ? 线程(thread)是一个程序内部的一条执行路径。 我们之前启动程序执行后,main方法的执行其实就是一条单独的执行路径。 程序中如果只有一条执行路径,那么这个程序就是单线程的程序。 什么是多线程 ? 多线程是指从软硬件上实现多条执行流程的技术。 方式一

    2024年02月20日
    浏览(13)
  • Appium/Selenium+Java的三种等待方式

    参考: java-selenium三种等待方式 Selenium+Java(六)Selenium 强制等待、显式等待、隐实等待 强制等待是利用time模块的sleep方法来实现,最简单粗暴的等待方法。 缺点:不能准确把握需要等待的时间(有时候操作未完成,等待就结束了,导致报错;有时候操作已经完成了,但时间

    2024年02月05日
    浏览(6)
  • 【Java面试题】线程创建的三种方式及区别?

    继承Thread类,子类重写run()方法,调用子类的strat()启动线程。 实现Runnable接口,实现run()方法,调用对象start()启动线程。 实现Callable接口,实现call()方法,用FutureTask()封装实现类。使用FutureTask对象作为Thread对象调用start()启动线程,调用FutureTask对象的get()

    2024年02月12日
    浏览(15)
  • 为Java应用创建Docker镜像的三种方式

    为Java应用创建Docker镜像的三种方式

    在 Dockerfiles 出现的很久之前,Java 开发者大多使用单体应用方式部署(WARs, JARs, EARs, 等等)。现在如你所知,最好的做法是为每个小业务单独部署的微服务方式。你构建的不是一个巨大的单体应用程序,而是使多个可以独立运行的小服务。 这正是 Docker 的用武之地。如果你想

    2023年04月26日
    浏览(13)
  • Java并发(三)----创建线程的三种方式及查看进程线程

    Java并发(三)----创建线程的三种方式及查看进程线程

    例如: 输出 注意:这里通过 @Slf4j 注解打印的日志 把【线程】和【任务】(要执行的代码)分开 Thread 代表线程 Runnable 可运行的任务(线程要执行的代码) 例如: 输出 Java 8 以后可以使用 lambda 精简代码 小结 方法1 是把线程和任务合并在了一起,方法2 是把线程和任务分开

    2023年04月24日
    浏览(10)
  • java篇-Springboot解决跨域问题的三种方式

    第一种:添加 @CrossOrigin 注解 在Controller层对应的方法上添加@CrossOrigin或者类上添加@CrossOrigin   第二种:添加CORS过滤器 新建配置类CorsConfig,创建 CorsFilter 过滤器,允许跨域  第三种:实现 WebMvcConfigurer ,重写 addCorsMappings 方法 全局配置有可能出现跨域失败的情况,改为过滤

    2024年04月23日
    浏览(10)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包