商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > C++调用java

C++调用java

  发布于2026-07-08 阅读(0)

扫一扫,手机访问

最近在做一个项目,需要从 C/C++ 环境直接调用 Ja va 类里的特定方法——注意,可不是用 system() 去启动一个 Ja va 进程,而是通过 JNI(Ja va Native Interface)在同一个进程空间里动态加载 JVM,找到对应的类,再调用其方法。听起来有点绕?把整个流程拆解开来,其实几步就能说清楚。

先给一个总体框架:

  1. Ja va 类编译成 .class 文件,并准备好对应的头文件和库文件(JNI 机制本身会生成头文件,但这里我们直接用 C++ 调用已有的 class,无需反向生成)。
  2. C/C++ 程序启动时,先创建 Ja va 虚拟机(JVM),然后通过 JNI 接口找到目标类和对应方法,最后正常调用。

下面按照实战步骤,把每个环节拆开细讲。

一、安装配置 Ja va 环境

我的实验环境是 RedHat Enterprise Linux 5,内核 2.6.18。安装 JDK 没什么特别的,去官网或者软件库下载对应 Linux 平台的安装包即可。我下载的是 jdk-1_5_0_06-linux-i586.bin,解压安装:

# mkdir /usr/local/ja va
# cd /usr/local/ja va
# cp /home/soft/jdk-1_5_0_06-linux-i586.bin ./
# chmod u+x jdk-1_5_0_06-linux-i586.bin
# ./jdk-1_5_0_06-linux-i586.bin

安装完成后,JDK 在 /usr/local/ja va/jdk1.5.0_06/。验证一下:

# cd jdk1.5.0_06/bin
# ./ja va -version
ja va version "1.5.0_06"
Ja va(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)
Ja va HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode, sharing)

然后是环境变量配置。这一步非常重要,尤其是 JRE_HOMELD_LIBRARY_PATH,后面编译 C++ 程序时要用到 JRE 下的 libjvm.so。我的设置如下:

export JA VA_HOME=/usr/local/ja va/jdk1.5.0_06
export PATH=$PATH:/usr/local/ja va/jre1.5.0_05/bin
export JRE_HOME=/usr/lib/jvm/ja va-1.4.2-gcj-1.4.2.0/jre
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$JRE_HOME/lib/i386:$JRE_HOME/lib/i386/client

注意,如果机器上没有 JRE 环境,需要先安装 JRE(安装方法与 JDK 类似),否则后续 libjvm.so 找不到,编译会报错。

设置完后可以检查变量是否生效:

[root@localhost bin]# echo $JA VA_HOME
/usr/local/ja va/jdk1.5.0_06

二、编写简单的 Ja va 程序

定义一个简单的 MyTest 类,放在包 com.test 下。包含一个静态方法 add 和一个实例方法 judge

package com.test;

public class MyTest {
    public MyTest(){
        super();
    }
    public static int add(int a,int b) {
        return a+b;
    }
    public boolean judge(boolean bool) {
        return !bool;
    }
}

编译:

# ja vac MyTest.ja va

编译后生成 MyTest.class,把它放到当前目录的 com/test 子目录下。C++ 程序在 JNI 查找时会按照全限定类名 com/test/MyTest 去寻找这个 class 文件。

三、C++ 程序

接下来是核心——C++ 端代码。包含必要的头文件,并实现两个辅助函数 stoJstringjstringTostring 用于 Ja va 字符串与 C 字符串之间的转换(本示例中虽然没直接用字符串,但保留作为通用工具)。main 函数内的流程就是标准的 JNI 调用步骤:

  1. 设置 JVM 启动参数(包括 classpath)。
  2. 调用 JNI_CreateJa vaVM 创建 Ja va 虚拟机。
  3. 通过 FindClass 找到目标类。
  4. 获取方法 ID —— 静态方法用 GetStaticMethodID,实例方法用 GetMethodID
  5. 调用方法(静态方法用 CallStaticIntMethod,实例方法需要先创建对象再调用)。
  6. 最后销毁 JVM。

完整代码如下:

#include 
#include 
#include 
#include 
#include 

jstring stoJstring(JNIEnv* env, const char* pat)
{
    jclass strClass = env->FindClass("ja va/lang/String");
    jmethodID ctorID = env->GetMethodID(strClass, "", "([BLja va/lang/String;)V");
    jbyteArray bytes = env->NewByteArray(strlen(pat));
    env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);
    jstring encoding = env->NewStringUTF("utf-8");
    return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);
}

char* jstringTostring(JNIEnv* env, jstring jstr)
{
    char* rtn = NULL;
    jclass clsstring = env->FindClass("ja va/lang/String");
    jstring strencode = env->NewStringUTF("utf-8");
    jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Lja va/lang/String;)[B");
    jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
    jsize alen = env->GetArrayLength(barr);
    jbyte* ba = env->GetByteArrayElements(barr,JNI_FALSE);
    if(alen > 0){
        rtn = (char*)malloc(alen + 1);
        memcpy(rtn, ba, alen);
        rtn[alen] = 0;
    }
    env->ReleaseByteArrayElements(barr, ba, 0);
    return rtn;
}

using namespace std;

int main()
{
    Ja vaVMOption options[2];
    JNIEnv *env;
    Ja vaVM *jvm;
    Ja vaVMInitArgs vm_args;
    long status;
    jclass cls;
    jmethodID mid;
    jint square;
    jboolean jnot;
    jobject jobj;

    options[0].optionString = "-Dja va.compiler=NONE";
    options[1].optionString = "-Dja va.class.path=.";
    // options[2].optionString = "-verbose:jni"; // 调试时可开启

    vm_args.version = JNI_VERSION_1_4;
    vm_args.nOptions = 2;
    vm_args.options = options;
    vm_args.ignoreUnrecognized = JNI_TRUE;

    status = JNI_CreateJa vaVM(&jvm, (void**)&env, &vm_args);

    if(status != JNI_ERR){
        printf("create ja va jvm success\n");
        cls = env->FindClass("com/test/MyTest");
        if(cls !=0){
            printf("find ja va class success\n");
            // 构造函数
            mid = env->GetMethodID(cls,"","()V");
            if(mid !=0){
                jobj=env->NewObject(cls,mid);
                std::cout << "init ok" << std::endl;
            }

            // 调用add静态函数
            mid = env->GetStaticMethodID( cls, "add", "(II)I");
            if(mid !=0){
                square = env->CallStaticIntMethod( cls, mid, 5,5);
                std::cout << square << std::endl;
            }

            // 调用judge实例函数
            mid = env->GetMethodID( cls, "judge","(Z)Z");
            if(mid !=0){
                jnot = env->CallBooleanMethod(jobj, mid, 1);
                if(!jnot) std::cout << "Boolean ok" << std::endl;
            }
        }
        else{
            fprintf(stderr, "FindClass failed\n");
        }

        jvm->DestroyJa vaVM();
        fprintf(stdout, "Ja va VM destory.\n");
        return 0;
    }
    else{
        printf("create ja va jvm fail\n");
        return -1;
    }
}

编译 C++ 程序时,需要链接 libjvm.so。注意编译命令中 -I 指定 JNI 头文件路径,-L 指定库文件路径。我这里使用的是 ${JRE_HOME}/lib/i386/client 下的 libjvm.so,而不是 ${JA VA_HOME} 下的。一开始我图省事用了 JDK 目录下的版本,结果运行时出现了令人崩溃的 SIGSEGV 错误:

# An unexpected error has been detected by HotSpot Virtual Machine:
#  SIGSEGV (0xb) at pc=0xb6d3dbe3, pid=14454, tid=2773482416
# Ja va VM: Ja va HotSpot(TM) Server VM (1.5.0_11-b03 mixed mode)
...

后来换成 JRE 下的 libjvm.so 就一切正常了。编译命令示例:

g++ -o testja va testja va.cpp -I${JA VA_HOME}/include -I${JA VA_HOME}/include/linux -L${JRE_HOME}/lib/i386/client -ljvm

编译完成后可以用 ldd testja va 检查链接库是否正确。

运行结果

[root@localhost jni]# ./testja va
create ja va jvm success
find ja va class success
init ok
10
Boolean ok
Ja va VM destory.

输出的 10 就是 add(5,5) 的结果,Boolean ok 说明 judge(true) 返回了 false(取反正确)。整个流程跑通,C++ 调用 Ja va 就完成了。

C++调用ja va

本文转载于:https://blog.csdn.net/crazyhacking/article/details/38081105 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注