闲碎记事本 闲碎记事本
首页
  • JAVA
  • Cloudflare
  • 学完再改一遍UI
友链
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

YAN

我要偷偷记录...
首页
  • JAVA
  • Cloudflare
  • 学完再改一遍UI
友链
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • java

    • SpringBoot

    • SpringSecurity

    • MybatisPlus

    • Netty

    • sip

    • 其他

      • MDC 使用
      • 位运算
      • RedisMQ实现
      • 自定义枚举序列化
      • Mybatis使用自定义枚举
      • Jackson反序列化泛型注意点
      • 敏感词过滤算法
      • 线程
      • 并发学习
      • jni使用
        • 关于注释
        • 为什么一个Byte用两个16进制表示
        • JAVA获取系统信息
        • 对extends和super的理解
        • JAVA系统API
        • java探针初探
        • JAVA获取USB信息
        • HashMap初探
        • JAVA远程调试
        • 初探webflux
        • SSE示例
    • linux

    • docker

    • redis

    • nginx

    • mysql

    • 其他

    • 环境搭建

    • 知识库
    • java
    • 其他
    YAN
    2023-07-29
    目录

    jni使用

    最近做的项目需要调用本地C++代码,正好在Java中可以通过JNI机制来支持内地代码的使用。

    下面记录下使用方式

    在使用之前我们首先得具备java和c++的开发能力,没有也没关系。我就只会写java,动态库让c++的同学提供就好。

    在不同的平台下,本地动态库的格式是不一样的:

    • windows -> .dll
    • 类UNIX平台- > .so

    首先创建一个java类

    
    package com.jni.demo;
    
    public class NativeLibraryDemo {
    
        private static native String fun1(String data);
    
        private static native String fun2(String data, String ip);
    }
    

    # 生成头文件

    在jdk8后使用如下命令

    javac -h . NativeLibraryDemo.java
    

    1.8之前自行查找吧,都java20了,该换了。

    头文件内容如下:

    
    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class com_jni_demo_NativeLibraryDemo */
    
    #ifndef _Included_com_jni_demo_NativeLibraryDemo
    #define _Included_com_jni_demo_NativeLibraryDemo
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    JNIEXPORT jstring JNICALL Java_com_jni_demo_NativeLibraryDemo_fun1
      (JNIEnv *, jclass, jstring);
    
    
    JNIEXPORT jstring JNICALL Java_com_jni_demo_NativeLibraryDemo_fun2
      (JNIEnv *, jclass, jstring, jstring);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    
    

    将java的native方法转换成C函数声明的规则是这样的:Java_{package_and_classname}_{function_name}(JNI arguments)。包名中的点换成单下划线。

    会发现多个几个参数:

    1. JNIEnv *:这是一个指向JNI运行环境的指针,后面我们会看到,我们通过这个指针访问JNI函数
    2. jobject:这里指代java中的this对象

    后面的话就可以交给C++的同学了。

    当你拿到了他给你的 dll/so 文件后,要在java程序中加载这个文件。

    下面记录两种方式:

    # 加载动态库路径

    在jvm启动参数中制定动态库路径:

     -Djava.library.path={具体放置动态库文件夹路径} 
    

    在NativeLibraryDemo静态代码块加入如下代码

    static {
        final String  LIBRARY_NAME = "demo";
        System.loadLibrary(LIBRARY_NAME); 
    }
    
    

    如果你不去配置启动参数,在程序中使用如下代码

    System.setProperty("java.library.path");
    

    当然是不行的。原因是java.library.path 这个路径在程序启动时就被ClassLoader加载了。

    可以通过反射大法修改,方法如下

        public static void addLibraryDir(String libraryPath) throws IOException {
            try {
                Field field = ClassLoader.class.getDeclaredField("usr_paths");
                field.setAccessible(true);
                String[] paths = (String[]) field.get(null);
                for (String path : paths) {
                    if (libraryPath.equals(path)) {
                        return;
                    }
                }
                String[] tmp = new String[paths.length + 1];
                System.arraycopy(paths, 0, tmp, 0, paths.length);
                tmp[paths.length] = libraryPath;
                field.set(null, tmp);
            } catch (IllegalAccessException e) {
                throw new IOException("未能获得库路径的权限");
            } catch (NoSuchFieldException e) {
                throw new IOException("没有找到库路径");
            }
        }
    

    最终代码

    static {
        addLibraryDir("你的动态库路径")
        final String  LIBRARY_NAME = "demo";
        System.loadLibrary(LIBRARY_NAME); 
    }
    

    # 加载动态库文件

    将动态库文件放在user.dir目录下 ,在NativeLibraryDemo静态代码块加入如下代码

    static{
        final String  LIBRARY_NAME = "demo";
        
        String userDir = System.getProperty("user.dir");
        
        if(isWindows()){
             return String.format("%s/%s.dll", userDir, LIBRARY_NAME);
        }
        if(isLinux()){
             return  String.format("%s/%s.so", userDir, LIBRARY_NAME);
        }
        throw new RuntimeException("不支持除Windows,Linux 之外的平台");
    }
    
    

    # 使用

    和正常java类一样使用

    参考链接 (opens new window)

    上次更新: 2025/05/22, 07:52:48
    并发学习
    关于注释

    ← 并发学习 关于注释→

    最近更新
    01
    Caddy操作指南
    04-25
    02
    虚拟机磁盘扩展
    04-22
    03
    Swap空间
    04-22
    更多文章>
    Theme by Vdoing | Copyright © 2022-2025 YAN | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式