从 C 调用 Java 方法而不从 C 启动 JVM

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*实例。这是在本机方法返回之前应使用的唯一实例,而不是任何旧的已保存实例。

Jac*_* G. 3

正如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文件。