Java JNI使用Demo
一个超完整、可直接运行的JNI实战示例,包含文件读取、数组计算、错误处理和跨平台说明。
这个例子就像给你的Java应用装了个"C语言外挂",性能提升看得见!💻
🌟 文件处理器 + 数组计算器
(代码Windows/Linux/Mac通用)
1️⃣ Java代码:FileProcessor.java
public class FileProcessor {
// 1. 读取文件内容
public native String readFileContent(String filePath);
// 2. 计算整数数组和
public native int calculateSum(int[] numbers);
static {
// 自动加载本地库(跨平台兼容)
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
System.load("fileprocessor.dll"); // Windows
} else if (os.contains("mac")) {
System.load("libfileprocessor.dylib"); // macOS
} else {
System.load("libfileprocessor.so"); // Linux
}
}
public static void main(String[] args) {
FileProcessor processor = new FileProcessor();
// ✅ 测试文件读取(需提前在当前目录创建test.txt)
System.out.println("文件内容: " + processor.readFileContent("test.txt"));
// ✅ 测试数组计算
int[] nums = {10, 20, 30, 40};
System.out.println("数组和: " + processor.calculateSum(nums));
}
}
💡 为什么这样写?
- 用System.getProperty("os.name")自动适配不同系统
- 避免了loadLibrary("fileprocessor")的平台依赖问题
2️⃣ 生成C头文件(关键步骤!)
# 1. 编译Java类
javac FileProcessor.java
# 2. 生成C头文件(JDK 10+标准命令)
javac -h ./ FileProcessor.java
✅ 生成文件:FileProcessor.h(在当前目录)
3️⃣ C实现:FileProcessor.c(核心逻辑)
#include "FileProcessor.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 读取文件内容 */
JNIEXPORT jstring JNICALL Java_FileProcessor_readFileContent(JNIEnv *env, jobject obj, jstring filePath) {
// 1. 转换Java字符串 → C字符串
const char *path = (*env)->GetStringUTFChars(env, filePath, NULL);
if (path == NULL) return NULL; // 空路径错误
// 2. 打开文件
FILE *file = fopen(path, "r");
if (file == NULL) {
(*env)->ReleaseStringUTFChars(env, filePath, path);
return (*env)->NewStringUTF(env, "ERROR: File not found");
}
// 3. 读取文件内容
fseek(file, 0, SEEK_END);
long size = ftell(file);
fseek(file, 0, SEEK_SET);
char *content = (char *)malloc(size + 1);
if (!content) {
fclose(file);
(*env)->ReleaseStringUTFChars(env, filePath, path);
return (*env)->NewStringUTF(env, "ERROR: Memory alloc failed");
}
fread(content, 1, size, file);
content[size] = '\0';
fclose(file);
// 4. 转换回Java字符串
jstring result = (*env)->NewStringUTF(env, content);
// 5. 释放资源
free(content);
(*env)->ReleaseStringUTFChars(env, filePath, path);
return result;
}
/* 计算数组和 */
JNIEXPORT jint JNICALL Java_FileProcessor_calculateSum(JNIEnv *env, jobject obj, jintArray numbers) {
// 1. 获取数组指针
jint *array = (*env)->GetIntArrayElements(env, numbers, NULL);
if (!array) return 0; // 数组为空
// 2. 计算和
jsize len = (*env)->GetArrayLength(env, numbers);
jint sum = 0;
for (int i = 0; i < len; i++) {
sum += array[i];
}
// 3. 释放数组
(*env)->ReleaseIntArrayElements(env, numbers, array, 0);
return sum;
}
🔥 关键亮点:
- ✅ 错误处理:文件不存在、内存不足都返回友好错误
- ✅ 内存安全:所有malloc都配了free,GetStringUTFChars配了Release
- ✅ 数组操作:用GetIntArrayElements安全访问Java数组
4️⃣ 编译步骤(三步走)
🟦 Windows (生成 fileprocessor.dll)
# 安装MinGW或使用VS的x64 Native Tools命令行
cl /LD FileProcessor.c
🟩 Linux (生成 libfileprocessor.so)
gcc -shared -o libfileprocessor.so FileProcessor.c
🟦 Mac (生成 libfileprocessor.dylib)
gcc -dynamiclib -o libfileprocessor.dylib FileProcessor.c
💡 注意:编译后将生成的文件(fileprocessor.dll/libfileprocessor.so/libfileprocessor.dylib)放到Java程序同目录
5️⃣ 运行前准备
- 在当前目录创建测试文件 test.txt(内容随便写,例如:Hello JNI!)
- 确保编译生成的本地库文件在当前目录
- 运行命令:
java FileProcessor
6️⃣ 预期输出
文件内容: Hello JNI!
数组和: 100
✅ 如果看到这个输出,说明你的JNI配置100%成功!🎉
⚠️ 新手常踩的坑 & 解决方案
| 问题 | 错误现象 | 解决方案 |
|---|---|---|
| java.lang.UnsatisfiedLinkError | 找不到库文件 | 确认库文件名+扩展名正确(Windows是.dll,Linux是libxxx.so) |
| file not found | 文件内容为空 | 确保test.txt在Java运行目录(不是代码目录) |
| Access violation | 程序崩溃 | 检查C代码是否漏了Release*(如ReleaseStringUTFChars) |
| 编译报错undefined reference | 缺少-shared | Linux/Mac必须用-shared编译 |
Java Native Interface (JNI) 是Java平台自1.1版本起提供的标准编程接口,允许Java程序与C/C++等本地代码进行交互。它主要解决纯Java环境无法处理的场景:当需要高性能计算(如图像处理、音视频编解码)、访问特定平台功能、复用现有C/C++库或与硬件交互时,JNI充当了Java与本地代码之间的桥梁。使用JNI时,Java层通过native关键字声明方法并加载本地库,生成头文件后在C/C++层实现具体逻辑,最终编译成动态链接库(Windows的.dll或Linux的.so)。虽然JNI能显著提升性能和功能扩展性,但其开发复杂度较高,需要同时掌握Java和C/C++,且调试难度较大。
- 感谢你赐予我前进的力量
赞赏者名单
因为你们的支持让我意识到写文章的价值🙏
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 软件从业者Hort
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果

