【发布时间】:2017-11-10 19:48:02
【问题描述】:
只是一个简单的问题: 是否可以从 c/c++ 调用 java 函数?
【问题讨论】:
只是一个简单的问题: 是否可以从 c/c++ 调用 java 函数?
【问题讨论】:
是的,你可以,但它有点复杂,并且以反射/非类型安全的方式工作(示例使用比 C 版本更简洁的 C++ api)。在这种情况下,它从 C 代码中创建 Java VM 的实例。如果您的本机代码首先从 Java 调用,则无需构造 VM 实例
#include<jni.h>
#include<stdio.h>
int main(int argc, char** argv) {
JavaVM *vm;
JNIEnv *env;
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_2;
vm_args.nOptions = 0;
vm_args.ignoreUnrecognized = 1;
// Construct a VM
jint res = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args);
// Construct a String
jstring jstr = env->NewStringUTF("Hello World");
// First get the class that contains the method you need to call
jclass clazz = env->FindClass("java/lang/String");
// Get the method that you want to call
jmethodID to_lower = env->GetMethodID(clazz, "toLowerCase",
"()Ljava/lang/String;");
// Call the method on the object
jobject result = env->CallObjectMethod(jstr, to_lower);
// Get a C-style string
const char* str = env->GetStringUTFChars((jstring) result, NULL);
printf("%s\n", str);
// Clean up
env->ReleaseStringUTFChars(jstr, str);
// Shutdown the VM.
vm->DestroyJavaVM();
}
编译(在 Ubuntu 上):
g++ -I/usr/lib/jvm/java-6-sun/include \
-I/usr/lib/jvm/java-6-sun/include/linux \
-L/usr/lib/jvm/java-6-sun/jre/lib/i386/server/ -ljvm jnitest.cc
注意:为了实现正确的错误处理,应该检查每个方法的返回码(为方便起见,我忽略了这一点)。例如
str = env->GetStringUTFChars(jstr, NULL);
if (str == NULL) {
return; /* out of memory */
}
【讨论】:
env->FindClass("HelloWorld");
是的,但您必须通过 JNI 进行:http://java.sun.com/javase/6/docs/technotes/guides/jni/index.html
【讨论】:
看看invocation API。这使您能够从在本机应用程序中加载和启动 JVM,然后从应用程序调用其上的方法。
简要(来自链接的文档)
/* load and initialize a Java VM, return a JNI interface
* pointer in env */
JNI_CreateJavaVM(&jvm, &env, &vm_args);
/* invoke the Main.test method using the JNI */
jclass cls = env->FindClass("Main");
jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V");
env->CallStaticVoidMethod(cls, mid, 100);
【讨论】:
是的,您可以从 C++ 或 C 调用 Java 函数,但除非您使用 COM 或 CORBA(或我可能不知道的其他第 3 方工具)之类的东西,否则您必须这样做在 JNI 的上下文中。
从本机代码调用 Java 方法的整个过程在 Sun 的 JNI 指南 pdf 中称为“调用方法”的第 4.2 节的第 4 章中进行了描述,您可以找到 here。
【讨论】:
以下函数允许您创建虚拟机。
JNIEnv* create_vm(JavaVM ** jvm)
{
JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption options[2];
options[0].optionString = "-Djava.class.path=.";
options[1].optionString = "-DXcheck:jni:pedantic";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 2;
vm_args.options = options;
vm_args.ignoreUnrecognized = JNI_TRUE; // remove unrecognized options
int ret = JNI_CreateJavaVM(jvm, (void**) &env, &vm_args);
if (ret < 0) printf("\n<<<<< Unable to Launch JVM >>>>>\n");
return env;
}
编译著名的Hello World 程序。以下函数尝试调用 HelloWorld 程序的 main 方法。
int main(int argc, char* argv[])
{
JNIEnv* env;
JavaVM* jvm;
env = create_vm(&jvm);
if (env == NULL) return 1;
jclass myClass = NULL;
jmethodID main = NULL;
myClass = env->FindClass("HelloWorld");
if (myClass != NULL)
main = env->GetStaticMethodID(myClass, "main", "([Ljava/lang/String;)V");
else
printf("Unable to find the requested class\n");
if (main != NULL)
{
env->CallStaticVoidMethod( myClass, main, " ");
}else printf("main method not found") ;
jvm->DestroyJavaVM();
return 0;
}
现在把 create_vm 函数和 main 函数放到一个 cpp 文件中,包含 jni.h 并编译它。我在 Windows 上使用了 MinGW。
g++ -D_JNI_IMPLEMENTATION_ -I"C:\Program Files\Java\jdk1.6.0_32\include" -I"C:\Program Files\Java\jdk1.6.0_32\include\win32" hello.cpp -L"C:\Program Files\Java\jre6\bin\client" -ljvm -o hello.exe
执行
现在如果你运行创建的 exe,你会得到一个错误。 jvm.dll not found 。
将 C:\Program Files\Java\jre6\bin\client 放入您的 PATH 环境变量中。现在你可以
运行exe文件。
注意:不要替换 jvm.dll 文件。
【讨论】:
上面的例子编码完成后,你需要对你的项目做一些配置。
在 Visual Studio 中将 jvm.lib 链接到您的项目的步骤:
完成这些步骤后,您的项目可以链接到 jvm 并正常运行。
【讨论】: