【问题标题】:Calling JNI function to create object调用 JNI 函数创建对象
【发布时间】:2019-05-18 18:46:23
【问题描述】:

我正在用 C11 编写 JNI 人员,并且有一个关于严格符合堆对象创建的问题。

JNI API 提供了执行此操作的函数,其签名如下:

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

6.5.2.2(p7) 标准中指定

函数原型声明器中的省略号表示 在最后一个声明的参数之后停止参数类型转换。

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

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
);

【问题讨论】:

    标签: java c jvm language-lawyer


    【解决方案1】:

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

    在您的情况下,Event 类的构造函数需要一个 int 和一个 String。

    所以它看起来像这样:

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

    测试

    为了执行一个简短的测试,我们可以编写一个类,该类调用一个本地 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-07
      • 2021-08-17
      • 1970-01-01
      • 2013-09-24
      • 2019-07-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多