当我们使用 Java程序调用C++程序时,我们可以使用JAVA_HOME类来访问 Java虚拟机中的类,并使用其提供的方法来调用 Java方法。 使用JAVA_HOME类调用 Java方法时,可以在 JVM中直接操作 Java虚拟机。这个方法称为“直接访问”(Direct Access),其基本思想是:如果类的引用指向了一个类的实例,那么就直接访问该实例。 在上面的例子中,我们通过以下方式来访问 Java虚拟机:
-
1.使用java_class类的静态方法
JAVA_HOME类提供了一种简单而有效的方法,即“静态方法”(Static Method),可以通过该类的静态方法来调用 Java虚拟机。 如果您不希望在 Java虚拟机上调用C++程序,那么可以使用静态方法。如果您希望使用静态方法而不是动态方法来调用 Java虚拟机,那么您可以通过使用JAVA_HOME类来实现此功能。下面是一个例子: 这个例子使用了JAVA_HOME类的静态方法。虽然调用的是 Java虚拟机中的一个类,但是却是以C++语言编写的,因为C++语言提供了一种叫做“可执行程序”(Executable Program)的机制,它可以将一个类转换为可执行文件是一种二进制文件,它可以被编译成可执行的二进制代码)。 如果您想用 Java程序来调用C++程序,那么可以使用 Java虚拟机中提供的“直接访问”(Direct Access)方法。我们可以看到,这个静态方法通过将 Java虚拟机中的“可执行文件”(可执行文件是一种二进制文件,它可以被编译成可执行程序)转换为C++语言,从而直接访问了 Java虚拟机。
-
2.使用 class参数来传递 Java方法的引用
我们可以使用 class参数来传递 Java方法的引用,如果我们想调用一个方法,可以在传入 class参数的时候将此方法的引用传递给 Java虚拟机。通过调用 class参数中的方法,我们可以在 Java虚拟机中调用该方法。 在上面的例子中,我们调用了 Java方法,并将引用传递给了 Java虚拟机。具体的实现如下: 在上面的例子中,我们使用 class参数来传递 Java方法的引用,并通过java_static修饰了这个参数。在调用 Java方法时, Java虚拟机检查此变量是否已经被设置为修饰了这个 class参数。 通过这种方式来调用 Java方法,我们可以调用 Java方法的所有参数(包括类、接口、常量等)。在上面的例子中,我们使用了一个名为`set_java_name_to_className`的参数来传递对象实例类型的值。通过这个参数,我们可以将 Java对象类型设置为`java_static`。如果我们想将这一参数传递给虚拟机中的类,可以使用如下代码: 上面两种方式都可以通过 class参数来传递 Java方法的引用。但是,它们之间有一个明显的区别:`set_java_name_to_className`中的值是虚拟机中类实例类型的值,而`set_java_name_to_className`中的值是类对象本身所对应的值。这是因为在编译成 class对象时,首先会将该对象转换为相应类实例类型所对应的值。这样,才能保证编译器在调用该类方法时能够正确地检查该方法对应于类实例类型。因此,在调用 Java方法时,我们需要通过` class参数`来传递 Java方法对应于类实例类型所对应的值。下面我们来看一下调用 Java方法时所需要执行的代码:
-
3.在 class中进行重写
在C++中,我们可以通过在 class中进行重写,来实现 Java中的直接访问方法。例如: 上述代码使用了 public static void*函数来实现 Java方法。 当我们调用C++程序时,可以通过在类的名称前加上“Java”后缀来实现直接访问。例如: 上面代码中,使用“Java”后缀可以在C++语言的文件名前加上“java”后缀,然后就可以使用 Java的直接访问方法了。 需要注意的是,我们在调用 Java方法时,必须首先定义好 class,并在 class中创建一个指向类实例的指针。只有当我们在类实例中定义好了一个名称为“java”的对象时,我们才能使用 Java的直接访问方法。下面我们通过实例来说明一下这种情况。 假设我们有一个名为“vector_name”的类,它是C++中的一个对象,同时还拥有一个名为“vector_name”的属性。例如: 上面代码中,使用“vector_name”后缀可以在类实例中创建一个指向该对象的指针,并使用它来访问该对象。 在上面例子中,我们定义了一个名为“vector_name”的类,并将它作为类实例添加到C++代码库中。为了方便地访问这个类,我们定义了两个参数: 将这两个参数传递给 Java虚拟机后,就可以在 Java虚拟机中直接调用C++程序了。由于这个对象是由一个名为“vector_name”的属性创建的,所以我们只能在 Java虚拟机中使用它。 最后要说明一下:C++中也可以通过重写类来调用 Java方法。例如: 上面代码中,我们在类的名称后加上了“*.c”后缀可以访问该方法。
-
4.在方法列表中查找调用该方法的对象
如果我们在方法列表中查找的对象是一个类,那么我们可以使用该对象的名称来访问该方法,也可以使用其接口来访问该对象。例如,我们可以在方法列表中查找“input”这个对象,并使用该对象的接口来访问它。 为了说明方法列表中的所有方法,我们假设这些方法都是通过接口调用的。例如,如果一个类声明了一个接口“address”,那么在类的实例中就可以找到“address”这个方法。
以下是常用的 C++ 调用 Java 代码示例:
1. 调用 Java 方法
```c++
#include <jni.h>
#include <iostream>
int main() {
JavaVM* jvm;
JNIEnv* env;
JavaVMInitArgs args;
JavaVMOption options[1];
jclass cls;
jmethodID mid;
jint square;
jintArray arr;
jint buf[10];
options[0].optionString = "-Djava.class.path=./";
args.version = JNI_VERSION_1_6;
args.nOptions = 1;
args.options = options;
args.ignoreUnrecognized = JNI_FALSE;
JNI_CreateJavaVM(&jvm, (void**)&env, &args);
cls = env->FindClass("Test");
mid = env->GetStaticMethodID(cls, "square", "([I)I");
arr = env->NewIntArray(10);
for (int i = 0; i < 10; i++) {
buf[i] = i;
}
env->SetIntArrayRegion(arr, 0, 10, buf);
square = env->CallStaticIntMethod(cls, mid, arr);
std::cout << "Square of 5 is " << square << std::endl;
jvm->DestroyJavaVM();
return 0;
}
```
2. 调用 Java 构造函数
```c++
#include <jni.h>
#include <iostream>
int main() {
JavaVM* jvm;
JNIEnv* env;
JavaVMInitArgs args;
JavaVMOption options[1];
jclass cls;
jmethodID mid;
jobject obj;
options[0].optionString = "-Djava.class.path=./";
args.version = JNI_VERSION_1_6;
args.nOptions = 1;
args.options = options;
args.ignoreUnrecognized = JNI_FALSE;
JNI_CreateJavaVM(&jvm, (void**)&env, &args);
cls = env->FindClass("Test");
mid = env->GetMethodID(cls, "<init>", "()V");
obj = env->NewObject(cls, mid);
jvm->DestroyJavaVM();
return 0;
}
```
3. 调用 Java 成员方法
```c++
#include <jni.h>
#include <iostream>
int main() {
JavaVM* jvm;
JNIEnv* env;
JavaVMInitArgs args;
JavaVMOption options[1];
jclass cls;
jmethodID mid;
jobject obj;
jstring str;
const char* cstr;
options[0].optionString = "-Djava.class.path=./";
args.version = JNI_VERSION_1_6;
args.nOptions = 1;
args.options = options;
args.ignoreUnrecognized = JNI_FALSE;
JNI_CreateJavaVM(&jvm, (void**)&env, &args);
cls = env->FindClass("Test");
mid = env->GetMethodID(cls, "printMessage", "(Ljava/lang/String;)V");
obj = env->AllocObject(cls);
str = env->NewStringUTF("Hello, world!");
env->CallVoidMethod(obj, mid, str);
jvm->DestroyJavaVM();
return 0;
}
```