Java中调用C代码

该文章已生成可运行项目,

在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头文件

  1. 编译Java类:
    javac -d . NativeDemo.java
    
  2. 生成头文件(JDK 8+使用javac -h):
    javac -h . NativeDemo.java
    
    生成的头文件NativeDemo.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!

关键注意事项

  1. 命名规则:C函数名必须遵循Java_ClassName_MethodName格式。
  2. 类型映射:使用JNI类型(如jstring, jint)与C类型转换。
    JNIEXPORT jstring JNICALL Java_MyClass_getMessage(JNIEnv *env, jobject obj) {
        return (*env)->NewStringUTF(env, "Message from C");
    }
    
  3. 内存管理:通过JNIEnv方法管理资源(如NewStringUTF, GetStringUTFChars)。
  4. 异常处理:在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源码地址

本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值