目录

  • 安装JDK及配置环境变量
  • 写Java代码
  • 生成头文件
  • 实现本地方法
  • 编译本地代码
  • 运行 Java 程序
  • 总结步骤


安装JDK及配置环境变量

参考:MAC系统安装JDK1.8及环境变量配置

写Java代码

// 文件名:Calculator.java
public class Calculator {
    // 声明本地方法
    public native int add(int a, int b);

    // 加载动态链接库
    static {
        try {
            System.load("/Users/zhanghao/Downloads/java_excise/jni示例/libcalculator.so");//这里必须使用绝对路径
        } catch (UnsatisfiedLinkError e) {
            System.err.println("Failed to load library: " + e.getMessage());
        }
    }

    public static void main(String[] args) {
        System.out.println("Ready to add!");
        Calculator calculator = new Calculator();
        int result = calculator.add(5, 3);
        System.out.println("Result: " + result);
    }
}

在这段 Java 代码中,我们声明了一个本地方法 add,它将在后面的 C 代码中实现。
我们还使用 System.loadLibrary 方法加载动态链接库libcalculator.so,它也将由后面的.c和.h文件生成。
注意到"/Users/zhanghao/Downloads/java_excise/jni示例/libcalculator.so"这个路径,他也是当前文件Calculator.java所在的路径。

生成头文件

在终端中,切换到包含 Java 代码的目录,并运行以下命令:

javac -h . Calculator.java
//新版JDK不支持javah指令,只能用javac -h

这步将生成2个文件,第1个是名叫 Calculator.h 的头文件,它包含了我们需要在 C 代码中实现的本地方法的声明。第2个是叫Calculator.class文件,它是Java 编译后的字节码文件,用于最后通过Java指令执行。如下图:

macbook的java目录在哪来_bc

其中,Calculator.h内容如下(第一行已经写明这是机器生成的文件,不需要改它):

macbook的java目录在哪来_c语言_02

实现本地方法

打开生成的头文件 Calculator.h看一下,并创建一个Calculator.c文件,在里面实现 Java_Calculator_add 方法。

// 文件名:Calculator.c
#include <stdio.h>
#include "Calculator.h"

JNIEXPORT jint JNICALL Java_Calculator_add(JNIEnv *env, jobject obj, jint a, jint b) {
    printf("in C program!\n");
    return a + b;
}

在这个 C 文件中,我们先是加了打印,然后实现了头文件中声明的本地方法 Java_Calculator_add,它将两个整数相加并返回结果。

编译本地代码

在终端中,使用 GCC 编译器,运行以下命令来编译本地代码,并生成动态链接库:

gcc -c -fPIC -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/darwin" Calculator.c
gcc -shared -o libcalculator.so Calculator.o

这将生成名为 libcalculator.so 的动态链接库文件,其中包含了我们的本地方法的实现。

解释一下这2条指令:
-c: 这个选项告诉编译器只进行编译,而不进行链接。这意味着它将产生一个目标文件而不是可执行文件。
-fPIC: 这个选项告诉编译器生成位置独立的代码(pasition independent code,这对于动态链接库(Shared Object)非常重要。
-I"xxx": 这个选项告诉编译器去 xxx 目录下查找头文件。在这个目录下,通常会有 jni.h , jni_md.h等 JNI 相关的头文件。
-shared表示生成一个共享库(动态库)文件。该条指令表示将 Calculator.o 这个目标文件编译并链接成一个名为 libcalculator.so 的共享库。

如果第一条指令失败,需要回头检查JDK的配置,通过echo $JAVA_HOME来查看Java的环境变量,如下图:

macbook的java目录在哪来_bc_03

运行 Java 程序

在终端中,运行以下命令来执行 Java 程序:

java Calculator

输出结果是:

macbook的java目录在哪来_Java_04

通过这个示例,我们可以了解到如何使用 JNI 来调用本地 C 代码,并将其集成到 Java 程序中。

总结步骤

共有下面几条指令:

//创建并撰写Calculator.java
javac -h . Calculator.java
//创建并撰写Calculator.c
gcc -c -fPIC -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/darwin" Calculator.c
gcc -shared -o libcalculator.so Calculator.o
java Calculator

共有下面6个文件

$ls
Calculator.c		Calculator.h		Calculator.o
Calculator.class	Calculator.java		libcalculator.so

其中只有.java和.c文件需要手动写,其余都是自动生成的。