如何从C++调用Java函数?

49

如何从C++应用程序中调用Java函数?

我知道可以通过CMD(或类似技术)来调用它们,但我不想使用它们。

4个回答

25
作为例子,可以查看从C语言创建JVM。它展示了创建JVM和调用方法的示例过程。如果JVM已经存在,例如您的C程序是由Java程序调用的(回调情况),则可以缓存JNIEnv*指针。
作为建议,请小心地缓存来自C/C++的JVM指针,因为涉及到一些语义问题,您可能稍后会被调用。因此,正如Brian Agnew所指出的那样,请查阅JNI参考文档。

这种调用方式正是我所寻找的。问题是这种方法的缺点是什么? - user63898
复杂度。但是我相信,根据我所读的,没有第三方工具,这是唯一的方法。 - bbqchickenrobot
回复:“如果JVM已经存在,例如您的C程序由Java程序调用(回调情况),则可以缓存JNIEnv*指针。”每个线程都有自己的JNIEnv,请勿在线程之间共享。 - Wheezil

19

请查看JNI调用接口。这将允许您在C(或C ++)应用程序中嵌入JVM。

请注意,存在各种更简单的机制来促进从Java调用C / C ++(例如JNA)。值得考虑倒转问题,以便您可以从Java进行调用(我理解对于您特定的应用程序可能无法实现此操作,但是这个思路也许是值得考虑的)


1
这不是你的错,但JNI调用接口链接已经断开。似乎Oracle移动了他们拥有的每一个JNI资源,因为当寻找JNI信息时,到处都是损坏的链接。 - StockB
看起来那个链接现在已经修复了。 - Brian Agnew

6
这个页面很有帮助: http://hildstrom.com/projects/jni/index.html 假设你有一个Java类:
package foo;
public class bar {
    public static int timesTen(int input){
        return input * 10;
    }
}

一旦你拥有了JVM和JNIEnv*(细节被省略了...),你可以按照以下方式从C++中调用Java方法:
jclass myClass = env->FindClass("foo.bar");
jmethodID mid = env->GetStaticMethodID(myClass, "timesTen", "(I)I");
jint hundred = env->CallStaticIntMethod(myClass, mid, (jint)10);

这只是概述,略去了很多细节,包括异常处理。如果忽略异常处理,会导致JVM崩溃。获取更详细的信息,请搜索“Java Native Interface”并查阅Oracle链接。
有人问起如何获取Env*。请注意,如果JVM调用了您的本地代码,则已经有了一个Env*。
JNIEnv* env(0);
jint rv = vm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (rv == JNI_OK) {
    return env;
} else if (rv == JNI_EDETACHED) {
    // This happens if you created the thread, not the JVM
    rv = vm->AttachCurrentThread((void**)&env, 0);
    if (rv != JNI_OK) {
        // error
    }
} else {
    // error
}

我想强调的是,使用JNI从C/C++调用Java非常繁琐且容易出错。错误往往具有密码学和低级特征。你必须处理异常,并且必须分离线程,否则会变得混乱不堪。


4
虽然这个链接可能回答了问题,但最好在这里包含回答的基本部分,并提供链接作为参考。仅有链接的答案如果链接页面更改,可能会变得无效。 - Perception
你从哪里获取 env - Nayuki
那就是“省略细节部分”;-) 基本上,你创建一个JVM,然后每个线程必须有一个Env。我添加了一小段代码片段。在退出之前,你还必须分离本地线程与JVM,否则会出现严重错误。 - Wheezil

-5

另一种从CPP调用Java方法的简单方法是通过批处理文件。

system() 

如何从CPP调用exe或bat文件的方法。将您的类与Java路径和类路径放在批处理文件中,并使用system("batch-file-name.bat")从CPP调用该批处理文件。

这很简单直接。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接