在Java中调用C代码通常通过Java本地接口(JNI,Java Native Interface)实现。以下是详细步骤和示例:
步骤 1:编写Java类并声明本地方法
public class NativeDemo {
// 声明本地方法(用native关键字修饰)
public native void printHello();
// 加载动态链接库(无需后缀)
static {
System.loadLibrary("nativeDemo");
}
public static void main(String[] args) {
new NativeDemo().printHello(); // 调用本地方法
}
}
步骤 2:生成JNI头文件
编译Java类:javac -d . NativeDemo.java
生成头文件(JDK 8+使用javac -h):javac -h . NativeDemo.java
生成的头文件NativeDemo.h内容如下:/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class NativeDemo */
#ifndef _Included_NativeDemo
#define _Included_NativeDemo
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_NativeDemo_printHello(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
步骤 3:编写C代码实现本地方法
创建NativeDemo.c文件,实现头文件中的函数:
#include
#include "NativeDemo.h" // 包含生成的头文件
JNIEXPORT void JNICALL Java_NativeDemo_printHello(JNIEnv *env, jobject obj) {
printf("Hello from C!\n");
}
步骤 4:编译C代码为动态链接库
Windows(生成DLL)
gcc -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" -shared -o nativeDemo.dll NativeDemo.c
Linux/macOS(生成.so/.dylib)
linux 平台
gcc -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" -I. -shared -o libnativeDemo.so org_example_NativeDemo.c
/bin/ld: /tmp/ccIbZfkB.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
gcc -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" -I. -shared -fPIC -o libnativeDemo.so org_example_NativeDemo.c
mac 平台
gcc -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/darwin" -I. -shared -o libnativeDemo.dylib org_example_NativeDemo.c
步骤 5:运行Java程序
确保动态库在Java的库路径中,可以通过以下方式指定:
java -Djava.library.path=. -cp . org.example.NativeDemo
输出:
Hello from C!
关键注意事项
命名规则:C函数名必须遵循Java_ClassName_MethodName格式。类型映射:使用JNI类型(如jstring, jint)与C类型转换。JNIEXPORT jstring JNICALL Java_MyClass_getMessage(JNIEnv *env, jobject obj) {
return (*env)->NewStringUTF(env, "Message from C");
}
内存管理:通过JNIEnv方法管理资源(如NewStringUTF, GetStringUTFChars)。异常处理:在C代码中抛出Java异常:jclass exClass = (*env)->FindClass(env, "java/lang/Exception");
(*env)->ThrowNew(env, exClass, "Error in C code");
替代方案:JNA(Java Native Access)
如果希望简化流程,可以使用JNA库,无需编写JNI代码:
import com.sun.jna.Library;
import com.sun.jna.Native;
public class JNADemo {
public interface CLibrary extends Library {
CLibrary INSTANCE = Native.load("c", CLibrary.class);
void printf(String format, Object... args);
}
public static void main(String[] args) {
CLibrary.INSTANCE.printf("Hello from C via JNA!\n");
}
}
通过以上步骤,即可在Java中成功调用C代码。根据需求选择JNI或JNA,前者性能更高,后者更简单。
gitee源码地址