Linux上从Java程序中调用C函数
原则上来说,“100%纯Java”的解决方法是最好的,但有些情况下必须使用本地方法。特别是在以下三种情况:
- 需要访问Java平台无法访问的系统特性和设备;
- 通过基准测试,发现Java代码比其他语言编写的等价代码慢得多;
- 其他语言编写的代码已经经过大量测试和调试,并且知道如何将其导出到所有的目标平台上。
Java平台有一个用于和本地C、C++代码进行互操作的API,称为Java本地接口(JNI)。下面将举例讨论Linux平台下的JNI编程。
1. 创建java类文件
创建一个nativeTest包,在包下新建HelloNative.java文件。
1 package nativeTest;
2
3 /**
4 * Created by jiax on 2016/12/30.
5 */
6 public class HelloNative {
7 // 静态初始化代码块,保证虚拟机在第一次使用该类时就会装载库
8 static {
9 System.loadLibrary( "HelloNative" );
10 }
11
12 // native 关键字表示本地方法,提醒编译器该方法将在外部定义
13 public static native void greeting();
14
15 // 测试greeting()函数
16 public static void main(String[] args) {
17 greeting();
18 }
19 }
2. 生成.h头文件
使用以下命令生成一个C的头文件,nativeTest_HelloNative.h
1 javac HelloNative.java
2 cd ..
3 javah nativeTest.HelloNative
生成的nativeTest_HelloNative.h如下:

1 /* DO NOT EDIT THIS FILE - it is machine generated */
2 #include <jni.h>
3 /* Header for class nativeTest_HelloNative */
4
5 #ifndef _Included_nativeTest_HelloNative
6 #define _Included_nativeTest_HelloNative
7 #ifdef __cplusplus
8 extern "C" {
9 #endif
10 /*
11 * Class: nativeTest_HelloNative
12 * Method: greeting
13 * Signature: ()V
14 */
15 JNIEXPORT void JNICALL Java_nativeTest_HelloNative_greeting
16 (JNIEnv *, jclass);
17
18 #ifdef __cplusplus
19 }
20 #endif
21 #endif
这个文件是在nativeTest文件夹外生成的,需要拖到nativeTest文件夹里面。
3. 创建.c文件
新建一个HelloNative.c文件,写出greeting()函数的实现代码。
1 #include <stdio.h>
2 #include "nativeTest_HelloNative.h"
3
4 JNIEXPORT void JNICALL Java_nativeTest_HelloNative_greeting(JNIEnv *env, jobject c1) {
5 printf("Hello Native!!\n");
6 }
4. 编译一个动态链接库
使用Linux下的gcc编译器,命令如下:
gcc -fPIC -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -shared -o libHelloNative.so HelloNative.c
生成libMyNative.so文件,此时整个nativeTest目录文件结构如下:
5. 运行测试
输入如下命令运行HelloNative.class文件。
java nativeTest.HelloNative
如果出现如下错误:
则需要把libHelloNative.so所在文件夹加入java.library.path,使用命令:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:..../nativeTest
最终结果如下。
6 总结
总的来说,将一个本地方法链接到Java程序中需要经过以下5个步骤:
- 在Java类中声明一个本地方法;
- 运行javah以获得包含该方法的C声明的头文件;
- 用C实现该本地方法;
- 将代码置于共享类库中;
- 在Java程序中加载该类库。
附录——本文中用到的工具版本
JDK——1.8.0_111
gcc——4.8.5
大悲无泪--大悟无言--大笑无声
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)