Som*_*ing 5 c java java-native-interface jnienv
我正在寻找有关如何使用 JNI 从 C 调用 Java 方法的教程。在我迄今为止找到的所有教程中,示例展示了如何首先从 C 创建 JVM。
我的应用程序从Java开始并使用JNI调用一些C函数。我现在需要从 C 调用一些 Java 函数,但我不想从 C 启动 JVM。
例如,是否可以创建一个用 C 实现的“本机”方法,并使用它来保存指针JNIEnv,然后重用它,而不是从 C 创建一个新的 JVM 实例来调用 Java方法?
有例子吗?
编辑:
看过这篇文章的人一定要小心!仅使用JNIEnv*来自当前 JNI 调用的实例!JNIEnv*如果您不想让程序崩溃,请不要保存和重用之前获得的任何指针。
在最好的情况下,使用旧的保存的指针可能会使您的应用程序崩溃。在更糟糕的情况下,它可能会导致难以调试和理解的低级不一致问题
不应缓存任何JNIEnv*实例,因为如果您的程序从 Java 启动,那么您的 C 代码无论如何都只能作为本机 java 方法执行,其 C 实现始终会获取相关的JNIEnv*实例。这是在本机方法返回之前应使用的唯一实例,而不是任何旧的已保存实例。
正如JJF所说,这绝对是可能的!我将在下面展示一个示例,假设您已经知道如何从 C 调用 Java 方法,但无需创建 JVM!
首先,我们有一个test.Test.java调用本机方法的Java 类methodA:
package test;
public class Test {
static {
System.loadLibrary("test");
}
private native void methodA();
public static void methodB() {
System.out.println("Java: Method B has executed!");
}
public static void main(String[] args) {
new Test().methodA();
}
}
Run Code Online (Sandbox Code Playgroud)
javah接下来,我们有由or创建的头文件javac -h:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class test_Test */
#ifndef _Included_test_Test
#define _Included_test_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: test_Test
* Method: methodA
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_test_Test_methodA
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
Run Code Online (Sandbox Code Playgroud)
下面是包含本机方法的 C 文件methodA:
#include <jni.h>
#include <stdio.h>
#include "test_Test.h"
void callMethodB(JNIEnv *env);
JNIEXPORT void JNICALL Java_test_Test_methodA(JNIEnv *env, jobject thisObj) {
printf("C: Method A executed!\n"); fflush(stdout);
callMethodB(env);
return;
}
void callMethodB(JNIEnv *env) {
jclass testClass = (*env) -> FindClass(env, "test/Test");
jmethodID methodB = (*env) -> GetStaticMethodID(env, testClass, "methodB", "()V");
(*env) -> CallStaticVoidMethod(env, testClass, methodB, NULL);
return;
}
Run Code Online (Sandbox Code Playgroud)
该程序的输出是:
C:方法A执行!
Java:方法B已执行!
请记住使用您首选的 GNU 编译器创建一个test.dll文件。