Java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别

JNA和JNI的区别

UnsatisfiedLinkError

在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种

  1. 类名错误
  2. 包名错误
  3. 方法名参数错误
  4. 使用 JNI 协议调用,结果 dll 未实现 JNI 协议需要使用 JNA 调用

这里需要特地说一下 JNI 和 JNA 是什么以及区别

JNI & JNA

JNI(Java Native Interface)

Java 原生接口:由 Java 官方提供的一种机制,用来调用 C/C++ 编写的函数。

特点在于 Java 和 C/C++ 也需要遵循这个规范,示例如下

C++代码: 其中JNIExport和JNICALL就是规范的一部分,其中方法命名格式如下Java_<包名_类名>_<方法名>对应的 Java 调用时也应该相同

1
2
3
4
extern "C" JNIEXPORT jint JNICALL
Java_com_example_JniDemo_add(JNIEnv* env, jobject obj, jint a, jint b) {
    return a + b;
}

Java 代码: 同样的在调用 dll 方法中你的类名和包名、方法名都需要和 dll 中一致

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
package com.example; // 包名对应 dll 方法中的包名
public class JniDemo {
    static {
        System.loadLibrary("native_lib"); // 加载 DLL
    }

    public native int add(int a, int b); // 声明 native 方法

    public static void main(String[] args) {
        System.out.println(new JniDemo().add(3, 4)); // 输出 7
    }
}

JNA(Java Native Access)

Java 开发的工具库,无需 JNI 编码,即可调用 DLL/so 中的 C 函数。

示例如下:

C++代码: 无需实现 JNI 规范

1
2
3
4
extern "C" __declspec(dllexport)
int add(int a, int b) {
    return a + b;
}

Java代码:使用 JNA 直接调用,需要导入 JNA 包

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import com.sun.jna.Library;
import com.sun.jna.Native;

public interface NativeLib extends Library {
    NativeLib INSTANCE = Native.load("native_lib", NativeLib.class);
    int add(int a, int b);
}

public class JnaDemo {
    public static void main(String[] args) {
        System.out.println(NativeLib.INSTANCE.add(3, 4)); // 输出 7
    }
}

总结

  • 如果厂商给你 普通 C/C++ DLL(非 JNI 风格):✅ 首选 JNA
  • 如果厂商只提供了带 JNI 的 DLL:✅ 只能用 JNI
  • 如果你自己控制底层 DLL、同时关注性能:✅ JNI 更灵活
  • 如果你要快速完成对接、项目周期紧:✅ JNA 开发效率极高