在Linux中,Java程序可以通过JNI(Java Native Interface)来调用C程序的方法。
Linux系统环境,Java调用C的主要流程如下:
1、创建Java类文件,如NativeLibrary.java
2、编写Java代码,加载.so共享库(C程序生成该名称的.so共享库),并声明本地方法
3、使用javac编译Java类,生成.class文件
4、使用javah对.class文件生成C头文件,该文件包含了Java和C之间通信所需的函数声明
5、创建C语言源文件,如NativeLibrary.c
6、编写C程序代码并实现要被Java调用的方法
7、使用gcc编译C程序和C头文件生成动态链接库(共享库.so文件)
8、运行Java程序,并调用C程序中的方法
1、Java类文件
创建NativeLibrary.java文件,内容如下:
public class NativeLibrary {
static {
System.loadLibrary("mylib"); // 加载名为"mylib"的共享库
}
public native void printHello(); // 声明本地方法
public static void main(String[] args) {
new Hello().printHello(); // 调用本地方法
}
}
其中,System.loadLibrary(“mylib”);为加载共享库, public native void printHello();为声明本地方法。
在Java中,加载本地库(通常是C或C++编写的库,以.dll、.so或.dylib等形式存在)主要有两种方式:System.loadLibrary()和System.load()。这两种方法用于与Java Native Interface (JNI)交互,使Java程序能够调用本地代码。
使用 System.loadLibrary()允许Java运行时根据平台自动定位和加载本地库。你只需要提供库的名字(不包括扩展名,如.dll或.so),Java运行时会在标准位置搜索这些库。
使用 System.load()允许你直接指定本地库的完整路径。这在库不在标准位置或需要加载特定版本的库时非常有用。
当使用System.loadLibrary()时,通常需要在linux环境设置环境变量LD_LIBRARY_PATH,如export LD_LIBRARY_PATH=“.so文件所在路径”
2、C头文件
javah是Java的一个命令行工具,用于生成JNI(Java Native Interface)的C或C++头文件。这些头文件包含了Java方法的本地签名,允许C或C++代码调用这些方法。当你需要编写本地代码来实现Java方法时,javah生成的头文件是非常有用的。
假设你有一个Java类MyClass,它位于包org.example中,并且你想要为这个类生成JNI头文件。以下是你需要遵循的步骤:
- 编写java类
- 编译java类,使用javac命令编译Java源文件。这一步骤会生成.class文件,javah工具需要这些文件才能工作。如,javac org/example/MyClass.java,注意.java文件所在的路径
- 使用javah生成C头文件,需要指定类的全限定名(包括包名)。如,javah -jni org.example.MyClass
- 生成.h文件,如org_example_NativeLibrary.h
C头文件内容如下
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class org_example_NativeLibrary */
#ifndef _Included_org_example_NativeLibrary
#define _Included_org_example_NativeLibrary
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: org_example_NativeLibrary
* Method: printHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_org_example_NativeLibrary_printHello
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
3、C程序文件
创建C程序文件,如NativeLibrary.c,内容如
#include <jni.h>
#include "org_example_NativeLibrary.h"
JNIEXPORT void JNICALL Java_org_example_NativeLibrary_printHello(JNIEnv *env, jobject obj) {
printf("Hello from C!\n");
}
其中,#include <jni.h>的jni.h文件来自jdk环境下,#include "NativeLibrary.h"来自使用javah生成的C头文件,Java_org_example_NativeLibrary_printHello需要和C头文件中的方法名称抱持一致。
4、共享库.so文件
编译C程序和头文件生成共享库,命令如下
gcc -shared -fpic -o libmylib.so -I$JAVA_HOME/include -I$JAVA_HOME/include/linux NativeLibrary.c
其中 libmylib.so为生成的共享库文件, -I
J
A
V
A
H
O
M
E
/
i
n
c
l
u
d
e
−
I
JAVA_HOME/include -I
JAVAHOME/include−IJAVA_HOME/include/linux为找C程序中的jni.h依赖,NativeLibrary.c为C程序文件,且C头文件需要和C程序文件在同一目录下。
在执行编译之前,请确保已经安装了gcc编译器,以及jdk环境。
5、运行Java程序
在linux环境中将.so共享库文件所在路径加入java.library.path中,设置环境变量,如下
export LD_LIBRARY_PATH=".so文件所在路径"
java ***类或java -jar ***包
结果类似如下