我如何实现两个名称相同但参数不同的 JNI 方法?

How can i implement two JNI methods with same name but different Params?

我有一个 java class,其中包含两个名称相同但参数不同的本机函数。

package com.example;

public class Test {

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

    public static native void doSomething(int a);
    public static native void doSomething(int a, long b);
}

我的头文件看起来像

#include <jni.h>

#ifndef _TEST_LIB_H_
#define _TEST_LIB_H_

#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT void JNICALL Java_com_example_Test_doSomething
    (JNIEnv *env, jclass clazz, jint a);

JNIEXPORT void JNICALL Java_com_example_Test_doSomething
    (JNIEnv *env, jclass clazz, jint a, jlong b);

#ifdef __cplusplus
}
#endif

#endif //_TEST_LIB_H_

和我的 cpp 文件

#include "TestLib.h"

JNIEXPORT void JNICALL Java_com_example_Test_doSomething
    (JNIEnv *env, jclass clazz, jint a){
    Java_com_example_Test_doSomething(env, clazz, a, -1);
}

JNIEXPORT void JNICALL Java_com_example_Test_doSomething
    (JNIEnv *env, jclass clazz, jint a, jlong b) {
    // implementation
}

只有一个功能有效,但在添加第二个具有相同名称和不同参数的功能后,我收到错误消息:

error: conflicting declaration of C function 'void Java_com_example_Test_doSomething(JNIEnv*, jclass, jint, jlong)'
note: previous declaration 'void Java_com_example_Test_doSomething(JNIEnv*, jclass, jint)'

我正在使用 android 工作室和实验性 gradle 插件。 我做错了什么?

首先,如果您的本机方法确实将 jclass 作为第二个参数,那么它们应该在 Java 端声明为 static。否则他们应该采用 jobject (调用它们的实例)而不是 jclass.


以下是 Oracle's documentation 关于重载本机方法命名的内容:

A native method name is concatenated from the following components: ... for overloaded native methods, two underscores (“__”) followed by the mangled argument signature

所以你的第二个函数的名称应该是Java_com_example_Test_doSomething__IJ。您可能还必须将第一个函数的名称更改为 Java_com_example_Test_doSomething__I.

使用javah工具生成头文件,下面是这个工具会为你的class.

生成的内容

要使用它,首先编译 .java 文件,然后 运行 javah 在 .class 文件上。

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_Test */

#ifndef _Included_com_example_Test
#define _Included_com_example_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_Test
 * Method:    doSomething
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_com_example_Test_doSomething__I
  (JNIEnv *, jobject, jint);

/*
 * Class:     com_example_Test
 * Method:    doSomething
 * Signature: (IJ)V
 */
JNIEXPORT void JNICALL Java_com_example_Test_doSomething__IJ
  (JNIEnv *, jobject, jint, jlong);

#ifdef __cplusplus
}
#endif
#endif