JNI传递对象参数的方法

December 16, 2011 / Java, JNI, 对象参数

1. 编写Java类

编写一个 Java 类ObjectTransmitter,ObjectTransmitter.java如下所示:

class TestObject {
    public int value;

    public void setValue(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}

public class ObjectTransmitter {
    public native void changeValue(TestObject obj);

    static {
        try {
            System.loadLibrary("ObjectTransmitter");
        } catch(UnsatisfiedLinkError e) {
            System.err.println( "Cannot load library:\n " +
                e.toString() );
        }
    }

    public static void main(String[] args) {
        ObjectTransmitter transmitter = new ObjectTransmitter();
        TestObject obj = new TestObject();
        obj.setValue(100);
        transmitter.changeValue(obj);
        System.out.println("Value: " + obj.getValue());
    }
}

编译ObjectTransmitter类:

javac ObjectTransmitter.java

2. 编写本地方法

生成头文件:

javah ObjectTransmitter

生成的ObjectTransmitter.h如下所示:

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

#ifndef _Included_ObjectTransmitter
#define _Included_ObjectTransmitter
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:     ObjectTransmitter
* Method:    changeValue
* Signature: (LTestObject;)V
*/
JNIEXPORT void JNICALL Java_ObjectTransmitter_changeValue
  (JNIEnv *, jobject, jobject);

#ifdef __cplusplus
}
#endif
#endif

实现本地方法,ObjectTransmitter.cpp如下所示

#include "ObjectTransmitter.h"

JNIEXPORT void JNICALL Java_ObjectTransmitter_changeValue
  (JNIEnv * env, jobject arg, jobject obj) {
    jclass clazz = env->GetObjectClass(obj);

    jfieldID fid = env->GetFieldID(clazz, "value", "I");
    jmethodID mid = env->GetMethodID(clazz, "setValue", "(I)V");
    int value = env->GetIntField(obj, fid);
    printf("Native value: %d\n", value);
    value *= 2;
    env->CallVoidMethod(obj, mid, value);

    return;
}

3. 相关函数说明

获取对象的属性或方法需要使用JNI提供的函数,如下所示:

JNIEnv * env;

env->GetFieldID(jclass clazz, const char *name, const char *sig);
env->GetXxxField(jobject obj, jfieldID fieldID);
env->SetXxxField(jobject obj, jfieldID fieldID, jint val);

env->GetStaticFieldID(jclass clazz, const char *name, const char *sig);
env->GetStaticXxxField(jclass clazz, jfieldID fieldID);
env->SetStaticXxxField(jclass clazz, jfieldID fieldID, jobject value);

env->GetMethodID(jclass clazz, const char *name, const char *sig”);
env->CallXxxMethod(jobject obj, jmethodID methodID, ...)

env->GetStaticMethodID(jclass clazz, const char *name, const char *sig);
env->CallStaticXxxMethod(jclass clazz, jmethodID methodID, ...);

其中Xxx是属性或方法返回值的类型,如Int、Void、Double等;sig是属性或方法签名,编码签名如下所示:

B     			byte
C     			char
D     			double
F     			float
I      			int
L     			long
Lclassname;	类的类型
S     			short
V     			void
Z     			boolean

方法签名的样式为(I)V,括号内为参数类型的签名。如果要查看TestObject类的类型签名,可以使用如下命令:

javap –s TestObject

4. 后记

关于共享库的编译以及Java程序的运行请参见《Hello JNI》。文中若有错误或疏漏之处,烦请批评指正。

5. 参考资料

  1. 《Java2核心技术》第七版, 第二卷, 第11章, 本地方法.