"Hello" 是 6 个 char 的常量缓冲区,其值为 H e l l o \0,其生命周期是整个程序。
std::string bob = "Hello";
将该缓冲区复制到std::string 对象中。 std::string 是一个值语义对象;这是 Java 往往缺乏的东西,因为所有对象都是通过引用隐式传递的。
options[0].optionString = (char *)"-Djava.class.path=.";
这是非常危险的。您将该缓冲区转换为指向char 的非const 指针,然后将其分配给optionString。
我不知道optionString 是什么,但如果它是char* 类型的变量,这会让你面临未定义的行为。对缓冲区"-Djava.class.path=." 的任何编辑都是未定义的行为,存储指向此类缓冲区的非const 指针只是在乞求这种情况发生。
简而言之,optionString 的类型是其危险程度的关键。这只是鲁莽,还是真的很愚蠢?
JavaVMOption* options = new JavaVMOption[1];
这会在堆上创建一个大小为1 的JavaVMOption 数组,然后存储指向options 中第一个元素的指针。
这里有很多无意义的东西。并且销毁它需要将它作为一个数组销毁?
JavaVMOption options;
这会在名为options 的堆栈上创建一个JavaVMOption。它在作用域结束时自动销毁。这似乎更实用。除非你需要new,否则使用new 是没有意义的,而在C++ 中你很少需要new。
我找到了一些示例代码:
#include <jni.h> /* where everything is defined */
...
JavaVM *jvm; /* denotes a Java VM */
JNIEnv *env; /* pointer to native method interface */
JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */
JavaVMOption* options = new JavaVMOption[1];
options[0].optionString = "-Djava.class.path=/usr/lib/java";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
/* load and initialize a Java VM, return a JNI interface
* pointer in env */
JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
delete options;
/* 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);
/* We are done. */
jvm->DestroyJavaVM();
这不是由以 C++ 编程为生的人编写的。
这是我最初的尝试:
struct destroy_java_vm {
void operator()(JavaVM* jvm)const{
jvm->DestroyJavaVM();
}
};
using up_java_vm = std::unique_ptr< JavaVM, destroy_java_vm >;
struct java_vm {
up_java_vm vm;
JNIEnv* env = 0;
};
struct java_vm_option {
std::string string;
std::shared_ptr<void> extra_info;
};
using java_vm_options = std::vector<java_vm_option>;
struct java_vm_init {
unsigned version = JNI_VERSION_1_2;
java_vm_options options;
bool ignore_unrecognized = false;
java_vm init() {
std::vector<JavaVMOption> java_options(options.size());
for (std::size_t i = 0; i < options.size(); ++i) {
java_options[i].optionString = &options.string[0];
java_options[i].extraInfo = options.extra_info.get();
}
JavaVMInitArgs args;
args.version = version;
args.options = java_options.data();
args.nOptions = java_options.size();
args.ignoreUnrecognized = ignore_unrecognized?TRUE:FALSE;
java_vm retval;
JavaVM* tmp = 0;
auto res = JNI_CreateJavaVM(&tmp, (void **)&retval.env, &args);
if (res < 0) {
return {}; // error message? How?
}
retval.vm.reset( tmp );
return retval;
}
}
用途:
java_vm_init init;
init.options.push_back("-Djava.class.path=.");
auto vm = init.init();
if (!vm.env) { return /* error case */; }
/* invoke the Main.test method using the JNI */
jclass cls = vm.env->FindClass("Main");
jmethodID mid = vm.env->GetStaticMethodID(cls, "test", "(I)V");
vm.env->CallStaticVoidMethod(cls, mid, 100);
/* We are done. */
根据我对unique_ptr 的使用,java_vm 对象是一种只能移动的值类型。当它被销毁时,java vm 会自动被销毁(如果你没有将它移出)。
当直接与 API 对话时,我们必须转向 C 风格的代码,因为许多跨语言 API 是使用 C 风格的接口编写的。我们将 C 风格的接口包装成更安全、更易于使用的 C++ 类型。
代码未经测试,可能包含拼写错误。