在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.javaNativeDemo.h内容如下:/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* 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 <stdio.h>
#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,前者性能更高,后者更简单。
2372

被折叠的 条评论
为什么被折叠?



