导读:本期聚焦于小伙伴创作的《C++怎么通过JNI与Java交互?C++调用Java方法与创建Java对象的本地接口技术详解》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C++怎么通过JNI与Java交互?C++调用Java方法与创建Java对象的本地接口技术详解》有用,将其分享出去将是对创作者最好的鼓励。

JNI基础概念与环境准备

JNI即Java Native Interface,是Java平台提供的一套标准编程接口,允许Java代码与用其他编程语言(如C、C++)编写的本地代码进行交互。在C++和Java交互的场景中,JNI主要承担桥梁的作用,让C++可以访问Java层的类、方法、对象等元素。

C++怎么通过JNI与Java交互?C++调用Java方法与创建Java对象的本地接口技术详解

要使用JNI进行开发,首先需要准备对应的环境:安装JDK并配置好环境变量,确保可以正常编译运行Java程序;安装C++编译工具,比如Windows下的MinGW或者Visual Studio,Linux下的GCC等。同时需要了解JNI中常用的数据类型映射,比如Java的int对应JNI的jint,Java的String对应JNI的jstring,这些映射关系是后续编写交互代码的基础。

C++调用Java静态方法

调用Java静态方法的流程相对简单,不需要先创建Java对象,直接通过类引用即可完成调用。下面通过一个示例来演示具体步骤。

第一步:编写Java类并声明本地方法

首先创建一个Java类,在其中声明一个静态方法和一个本地方法,本地方法由C++实现,用于触发对Java静态方法的调用。

public class JniDemo {
    // 静态方法,将被C++调用
    public static int add(int a, int b) {
        return a + b;
    }

    // 本地方法,C++实现该方法,内部调用add静态方法
    public native int callJavaStaticAdd(int a, int b);

    static {
        // 加载本地动态库,Windows下为JniDemo.dll,Linux下为libJniDemo.so
        System.loadLibrary("JniDemo");
    }

    public static void main(String[] args) {
        JniDemo demo = new JniDemo();
        int result = demo.callJavaStaticAdd(3, 5);
        System.out.println("调用Java静态方法结果:" + result);
    }
}

第二步:生成JNI头文件

使用javac编译Java类,然后通过javah命令生成对应的JNI头文件,头文件中会包含本地方法的函数声明。

javac JniDemo.java
javah -jni JniDemo

生成的JniDemo.h头文件中会包含类似如下的函数声明:

JNIEXPORT jint JNICALL Java_JniDemo_callJavaStaticAdd
  (JNIEnv *, jobject, jint, jint);

第三步:实现C++本地方法

编写C++代码实现上述声明的函数,在函数中通过JNIEnv指针找到Java类,再获取静态方法ID,最后调用静态方法。

#include <jni.h>
#include "JniDemo.h"
#include <iostream>

JNIEXPORT jint JNICALL Java_JniDemo_callJavaStaticAdd
  (JNIEnv *env, jobject obj, jint a, jint b) {
    // 1. 找到对应的Java类,参数是类的全限定名,点换成/
    jclass clazz = env->FindClass("JniDemo");
    if (clazz == nullptr) {
        std::cout << "找不到JniDemo类" << std::endl;
        return -1;
    }

    // 2. 获取静态方法ID,参数分别是类、方法名、方法签名
    // 方法签名格式:(参数类型)返回值类型,int类型对应I,所以(int,int)int的签名是(II)I
    jmethodID staticMethodId = env->GetStaticMethodID(clazz, "add", "(II)I");
    if (staticMethodId == nullptr) {
        std::cout << "找不到add静态方法" << std::endl;
        return -1;
    }

    // 3. 调用静态方法,传入类、方法ID、参数
    jint result = env->CallStaticIntMethod(clazz, staticMethodId, a, b);
    return result;
}

第四步:编译运行

将C++代码编译为动态库,然后运行Java程序即可看到调用结果。Windows下编译命令参考:

g++ -I"%JAVA_HOME%include" -I"%JAVA_HOME%includewin32" -shared -o JniDemo.dll JniDemo.cpp

运行Java程序后,会输出调用Java静态方法结果:8,说明C++成功调用了Java的静态方法。

C++调用Java实例方法

调用Java实例方法需要先创建或者获取到Java对象实例,再通过实例对象调用对应的方法,流程和调用静态方法类似,只是多了获取对象实例的步骤。

Java类定义

修改之前的JniDemo类,添加一个实例方法和对应的本地方法:

public class JniDemo {
    // 实例变量
    private int num;

    // 实例方法
    public int multiply(int a) {
        return num * a;
    }

    // 设置num值的方法
    public void setNum(int num) {
        this.num = num;
    }

    // 本地方法,调用实例方法multiply
    public native int callJavaInstanceMultiply(int a);

    static {
        System.loadLibrary("JniDemo");
    }

    public static void main(String[] args) {
        JniDemo demo = new JniDemo();
        demo.setNum(4);
        int result = demo.callJavaInstanceMultiply(5);
        System.out.println("调用Java实例方法结果:" + result);
    }
}

C++实现代码

在C++的本地方法中,首先获取Java对象实例,再获取实例方法ID,最后调用实例方法。

#include <jni.h>
#include "JniDemo.h"
#include <iostream>

JNIEXPORT jint JNICALL Java_JniDemo_callJavaInstanceMultiply
  (JNIEnv *env, jobject obj, jint a) {
    // 1. 获取对象对应的类
    jclass clazz = env->GetObjectClass(obj);
    if (clazz == nullptr) {
        std::cout << "获取对象类失败" << std::endl;
        return -1;
    }

    // 2. 获取实例方法ID,multiply方法参数是int,返回int,签名是(I)I
    jmethodID instanceMethodId = env->GetMethodID(clazz, "multiply", "(I)I");
    if (instanceMethodId == nullptr) {
        std::cout << "找不到multiply实例方法" << std::endl;
        return -1;
    }

    // 3. 调用实例方法,传入对象实例、方法ID、参数
    jint result = env->CallIntMethod(obj, instanceMethodId, a);
    return result;
}

运行Java程序后,会输出调用Java实例方法结果:20,说明C++成功调用了Java的实例方法。

C++中创建Java对象

在C++中也可以主动创建Java对象,不需要依赖Java层先创建好实例,主要步骤是找到类的构造方法,然后调用构造方法创建对象。

Java类定义

创建一个简单的Java类User,包含构造方法和实例方法:

public class User {
    private String name;
    private int age;

    // 构造方法
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 获取用户信息的方法
    public String getUserInfo() {
        return "姓名:" + name + ",年龄:" + age;
    }
}

修改JniDemo类,添加创建User对象的本地方法:

public class JniDemo {
    // 本地方法,创建User对象并调用getUserInfo方法
    public native String createJavaUser();

    static {
        System.loadLibrary("JniDemo");
    }

    public static void main(String[] args) {
        JniDemo demo = new JniDemo();
        String userInfo = demo.createJavaUser();
        System.out.println("创建的Java用户信息:" + userInfo);
    }
}

C++实现创建对象逻辑

构造方法在JNI中对应的方法名是<init>,通过获取构造方法ID,再调用NewObject方法即可创建对象。

#include <jni.h>
#include "JniDemo.h"
#include <iostream>

JNIEXPORT jstring JNICALL Java_JniDemo_createJavaUser
  (JNIEnv *env, jobject obj) {
    // 1. 找到User类
    jclass userClass = env->FindClass("User");
    if (userClass == nullptr) {
        std::cout << "找不到User类" << std::endl;
        return nullptr;
    }

    // 2. 获取构造方法ID,构造方法参数是String和int,返回void,签名是(Ljava/lang/String;I)V
    jmethodID constructorId = env->GetMethodID(userClass, "<init>", "(Ljava/lang/String;I)V");
    if (constructorId == nullptr) {
        std::cout << "找不到User构造方法" << std::endl;
        return nullptr;
    }

    // 3. 创建构造方法的参数,jstring类型需要转换
    jstring name = env->NewStringUTF("张三");
    jint age = 25;

    // 4. 调用构造方法创建User对象
    jobject userObj = env->NewObject(userClass, constructorId, name, age);
    if (userObj == nullptr) {
        std::cout << "创建User对象失败" << std::endl;
        return nullptr;
    }

    // 5. 获取getUserInfo方法ID,返回String,签名是()Ljava/lang/String;
    jmethodID getUserInfoId = env->GetMethodID(userClass, "getUserInfo", "()Ljava/lang/String;");
    if (getUserInfoId == nullptr) {
        std::cout << "找不到getUserInfo方法" << std::endl;
        return nullptr;
    }

    // 6. 调用getUserInfo方法获取用户信息
    jstring userInfo = (jstring)env->CallObjectMethod(userObj, getUserInfoId);

    // 释放局部引用,避免内存泄漏
    env->DeleteLocalRef(name);
    env->DeleteLocalRef(userObj);

    return userInfo;
}

运行Java程序后,会输出创建的Java用户信息:姓名:张三,年龄:25,说明C++成功创建了Java对象并调用了其方法。

JNI交互注意事项

  • JNI中的引用分为局部引用和全局引用,局部引用在函数执行结束后会自动释放,如果需要长期保存对象,需要转换为全局引用。
  • 方法签名的编写要准确,错误的签名会导致找不到方法,常见的类型签名:void对应V,boolean对应Z,byte对应B,char对应C,short对应S,int对应I,long对应J,float对应F,double对应D,类对应L全限定名;,数组对应[类型。
  • 及时释放不再使用的JNI引用,避免造成内存泄漏,尤其是创建大量对象或者频繁调用本地方法时。
  • JNIEnv指针是每个线程独有的,不能跨线程使用,如果需要跨线程操作,需要通过JavaVM指针获取对应线程的JNIEnv。

JNIC++Java本地接口修改时间:2026-07-11 18:30:41

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。