java - 调用 JNI 函数创建对象

标签 java c jvm language-lawyer

我正在编写 C11 中的 JNI 人员,并且对严格符合堆上对象创建有疑问。

JNI API提供了一个函数来使用以下签名来执行此操作:

jobject NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...);

按照 6.5.2.2(p7) 标准中的规定

The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter.

与省略号相对应的参数应显式转换为预期类型,以使代码符合要求。考虑以下情况:

public class Event{
    public final int eventType;
    public final String meta;

    public Event(int eventType, String meta){
        this.eventType = eventType;
        this.meta = meta;
    }
}

我应该将省略号对应的参数转换成什么类型​​的参数?

我猜它应该如下所示:

jclass event_class = ((*env)->FindClass)(env, "f/q/c/n/Event");
jmethodID ctor = (*env)->GetMethodID(
    env, 
    event_class, 
    "<init>", 
    "(ILjava/lang/String;)V"
);
array_element = (*env)->NewObject(
    env, 
    event_class, 
    ctor, 
    (jint) 0, (jobject) NULL //corresponds to the ellipsis
);

最佳答案

参数的类型是从您调用的方法中推导出来的。

在您的例子中,是 Event 类的构造函数需要一个 int 和一个 String。

所以它看起来像这样:

jstring metaStr = (*env)->NewStringUTF(env, "hello");

jobject array_element = (*env)->NewObject(
        env,
        event_class,
        ctor,
        (jint)4711, metaStr
);

测试

为了执行一个简短的测试,我们可以编写一个调用 native C 函数的类,该函数创建所需的 Event 对象,对其进行初始化,并将其返回给调用 Java 端。

这个 Java 程序看起来像这样:

import f.q.c.n.Event;

public class JNIEventTest {

    static {
        System.loadLibrary("native");
    }

    private native Event retrieveNativeEvent();


    public static void main(String[] args) {
        JNIEventTest jniEventTest = new JNIEventTest();
        Event event = jniEventTest.retrieveNativeEvent();
        System.out.println("eventType: " + event.eventType);
        System.out.println("meta: " + event.meta);
    }
}

原生的 C 端看起来像这样:

#include "JNIEventTest.h"

JNIEXPORT jobject JNICALL Java_JNIEventTest_retrieveNativeEvent(JNIEnv *env, jobject thisObject) {


    jclass event_class = ((*env)->FindClass)(env, "f/q/c/n/Event");
    jmethodID ctor = (*env)->GetMethodID(
            env,
            event_class,
            "<init>",
            "(ILjava/lang/String;)V"
    );

    jstring eventStr = (*env)->NewStringUTF(env, "hello");

    jobject array_element = (*env)->NewObject(
            env,
            event_class,
            ctor,
            (jint)4711, eventStr
    );

    return array_element;
}

控制台中的调试输出如下所示:

eventType: 4711
meta: hello

关于java - 调用 JNI 函数创建对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56201913/

相关文章:

java - 使用 collect 保留 Java 流中的顺序

java - 如何诊断或检测 Java 静态初始化程序中的死锁

java - 使用rmi注册表确定java rmi远程对象主机的ip

java - 多重继承和类对象

java - 将整数插入 TreeMap

C- 对 <函数名称> 的 undefined reference

c - 如何在 C 中打开 4 个字符的字符串?

c - C语言如何将2字节二进制转换为整数

java - 在java中动态加载Jar文件

java - Java 应用程序的入口点 : main(), init() 还是 run()?