jni java共享变量_Java Native Interfce三在JNI中使用Java类的普通方法与变量

本文是《The Java Native Interface Programmer’s Guide and Specification》读书笔记

前面我们学习了如何在JNI中通过参数来使用Java中的普通变量,下面我们来学习如何在JNI中使用Java类的普通方法与成员变量;Java中类有两个区域:每个类的实例的私有区域和所有实例共享的类的静态区域,JNI也提供了相应的方法来操作这两个区域中的方法与变量。首先以一个简单例子来说明如何在JNI中操作类实例的私有区域:

1 变量的操作

1.1 类实例的私有区域(成员变量)操作:

Java类的代码为:

class InstanceFieldAccess {

private String s;//类实例的私有区域,修饰符也可以为public

//JNI方法,用来修改类实例的私有区域的变量

private native void accessField();

public static void main(String args[]) {

InstanceFieldAccess c = new InstanceFieldAccess();

c.s = "abc";

c.accessField();

System.out.println("In Java:");

System.out.println(" c.s = \"" + c.s + "\"");

}

static {

System.loadLibrary("InstanceFieldAccess");

}

}

JNI方法的实现为:

JNIEXPORT void JNICALL

Java_InstanceFieldAccess_accessField(JNIEnv *env, jobject obj)

{

jfieldID fid; /* 保存区域的标识符 */

jstring jstr;

const char *str;

/* 得到obj对象的类的引用,这里是前面的类InstanceFieldAccess的引用 */

jclass cls = (*env)->GetObjectClass(env, obj);

printf("In C:\n");

/* 在类的私有区域里寻找名为s的区域标识 */

fid = (*env)->GetFieldID(env, cls, "s",

"Ljava/lang/String;");

if (fid == NULL) {

return; /* failed to find the field */

}

/* 取得相应区域标识的实例*/

jstr = (*env)->GetObjectField(env, obj, fid);

str = (*env)->GetStringUTFChars(env, jstr, NULL);

if (str == NULL) {

return; /* out of memory */

}

printf(" c.s = \"%s\"\n", str);

(*env)->ReleaseStringUTFChars(env, jstr, str);

/* 创建一个新的String对象 */

jstr = (*env)->NewStringUTF(env, "123");

if (jstr == NULL) {

return; /* out of memory */

}

/*将创建的String对象的值写入到相应区域标识里*/

(*env)->SetObjectField(env, obj, fid, jstr);

}

执行完这个JNI方法后,s的值就被修改为"123"了;

1.2 对类的静态区域的(类变量)操作

Java类的定义为:

public StaticFieldAccess{

private static int si;

private native void accessField();

...

}

对应的JNI的方法的实现为:

JNIEXPORT void JNICALL

Java_StaticFieldAccess_accessField(JNIEnv *env, jobject obj)

{

jfieldID fid; /*用来保存区域的标识 */

jint si;

/* Get a reference to obj’s class */

jclass cls = (*env)->GetObjectClass(env, obj);

printf("In C:\n");

/* Look for the static field si in cls */

fid = (*env)->GetStaticFieldID(env, cls, "si", "I");

if (fid == NULL) {

return; /* field not found */

}

/* Access the static field si */

si = (*env)->GetStaticIntField(env, cls, fid);

printf(" StaticFieldAccess.si = %d\n", si);

(*env)->SetStaticIntField(env, cls, fid, 200);

}

由上可以看出,在JNI中操作类实例的私有区域与操作类的静态区域是类似的,在得到区域的标识时,使用不同的方法就可以了。前面的操作看起来比较复杂,是因为String不是基本的类型,需要一些特殊的处理,而int为基本类型,不需要进行特殊的处理;

2. 普通方法的使用

2.1 类的实例的成员方法的使用

Java中类的定义如下:

public class InstanceMethodCall{

private native void nativeMethod();

private void callback(){

System.out.println("In Java");

}

...

}

JNI方法的实现

JNIEXPORT void JNICALL

Java_InstanceMethodCall_nativeMethod(JNIEnv *env, jobject obj)

{

jclass cls = (*env)->GetObjectClass(env, obj);

//得到对应方法的标识ID

jmethodID mid =

(*env)->GetMethodID(env, cls, "callback", "()V");

if (mid == NULL) {

return; /* method not found */

}

printf("In C\n");

//调用对应的成员方法,相应的还有CallIntMethod方法调用返回值为int的方法,CallObjectMethod方法调用返回值为对象的方法(数组,String等)等;

(*env)->CallVoidMethod(env, obj, mid);

}

JNI方法调用类的普通方法的流程参考以上代码;

2.2类方法的使用

java类的定义如下:

public class StaticMethodCall{

private native void nativeMethod();

private static void callback(){

System.out.println("In java");

}

...

}

对应的JNI方法的实现为:

JNIEXPORT void JNICALL

Java_StaticMethodCall_nativeMethod(JNIEnv *env, jobject obj)

{

jclass cls = (*env)->GetObjectClass(env, obj);

jmethodID mid =

(*env)->GetStaticMethodID(env, cls, "callback", "()V");

if (mid == NULL) {

return; /* method not found */

}

printf("In C\n");

(*env)->CallStaticVoidMethod(env, cls , mid);

}

类方法与类的实例的成员方法的调用也类似,只不过在获得方法标识时,需要调用不同的方法;

2.3 构造方法的调用

构造方法的调用与实例的成员方法的调用类似,下面以字符串的构造函数String(char[]chars)的调用为例:

jstring

MyNewString(JNIEnv *env, jchar *chars, jint len)

{

jclass stringClass;

jmethodID cid;

jcharArray elemArr;

jstring result;

stringClass = (*env)->FindClass(env, "java/lang/String");

if (stringClass == NULL) {

return NULL; /* exception thrown */

}

/* 得到构造函数String(char[]) 的方法标识 */

cid = (*env)->GetMethodID(env, stringClass,

"", "([C)V");

if (cid == NULL) {

return NULL; /* exception thrown */

}

/* 创建一个charArray来保存这些字符 */

elemArr = (*env)->NewCharArray(env, len);

if (elemArr == NULL) {

return NULL; /* exception thrown */

}

(*env)->SetCharArrayRegion(env, elemArr, 0, len, chars);

/* 构造一个 java.lang.String的对象,这就是调用构造函数的地方 */

result = (*env)->NewObject(env, stringClass, cid, elemArr);

/* 释放掉本地的引用 */

(*env)->DeleteLocalRef(env, elemArr);

(*env)->DeleteLocalRef(env, stringClass);

return result;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值