jni java共享变量_JNI/NDK开发指南(七)——C/C++访问Java实例变量和静态变量 .

在上一章中我们学习到了如何在本地代码中访问任意Java类中的静态方法和实例方法,本章我们也通过一个示例来学习Java中的实例变量和静态变量,在本地代码中如何来访问和修改。静态变量也称为类变量(属性),在所有实例对象中共享同一份数据,可以直接通过【类名.变量名】来访问。实例变量也称为成员变量(属性),每个实例都拥有一份实例变量数据的拷贝,它们之间修改后的数据互不影响。下面看一个例子:

packagecom.study.jnilearn;

publicclassAccessField {

privatenativestaticvoidaccessInstanceField(ClassField obj);

privatenativestaticvoidaccessStaticField();

publicstaticvoidmain(String[] args) {

ClassField obj =newClassField();

obj.setNum(10);

obj.setStr("Hello");

// 本地代码访问和修改ClassField为中的静态属性num

accessStaticField();

accessInstanceField(obj);

// 输出本地代码修改过后的值

System.out.println("In Java--->ClassField.num = "+ obj.getNum());

System.out.println("In Java--->ClassField.str = "+ obj.getStr());

}

static{

System.loadLibrary("AccessField");

}

}

package com.study.jnilearn;

public class AccessField {

private native static void accessInstanceField(ClassField obj);

private native static void accessStaticField();

public static void main(String[] args) {

ClassField obj = new ClassField();

obj.setNum(10);

obj.setStr("Hello");

// 本地代码访问和修改ClassField为中的静态属性num

accessStaticField();

accessInstanceField(obj);

// 输出本地代码修改过后的值

System.out.println("In Java--->ClassField.num = " + obj.getNum());

System.out.println("In Java--->ClassField.str = " + obj.getStr());

}

static {

System.loadLibrary("AccessField");

}

}

AccessField是程序的入口类,定义了两个native方法:accessInstanceField和accessStaticField,分别用于演示在本地代码中访问Java类中的实例变量和静态变量。其中accessInstaceField方法访问的是类的实例变量,所以该方法需要一个ClassField实例作为形参,用于访问该对象中的实例变量。

packagecom.study.jnilearn;

publicclassClassField {

privatestaticintnum;

privateString str;

publicintgetNum() {

returnnum;

}

publicvoidsetNum(intnum) {

ClassField.num = num;

}

publicString getStr() {

returnstr;

}

publicvoidsetStr(String str) {

this.str = str;

}

}

package com.study.jnilearn;

public class ClassField {

private static int num;

private String str;

public int getNum() {

return num;

}

public void setNum(int num) {

ClassField.num = num;

}

public String getStr() {

return str;

}

public void setStr(String str) {

this.str = str;

}

}

在本例中没有将实例变量和静态变量定义在程序入口类中,新建了一个ClassField的类来定义类的属性,目的是为了加深在C/C++代码中可以访问任意Java类中的属性。在这个类中定义了一个int类型的实例变量num,和一个java.lang.String类型的静态变量str。这两个变量会被本地代码访问和修改。

#include

#ifndef _Included_com_study_jnilearn_AccessField

#define _Included_com_study_jnilearn_AccessField

#ifdef __cplusplus

extern"C"{

#endif

JNIEXPORTvoidJNICALL Java_com_study_jnilearn_AccessField_accessInstanceField

(JNIEnv *, jclass, jobject);

JNIEXPORTvoidJNICALL Java_com_study_jnilearn_AccessField_accessStaticField

(JNIEnv *, jclass);

#ifdef __cplusplus

}

#endif

#endif

#include

#ifndef _Included_com_study_jnilearn_AccessField

#define _Included_com_study_jnilearn_AccessField

#ifdef __cplusplus

extern "C" {

#endif

JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessField_accessInstanceField

(JNIEnv *, jclass, jobject);

JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessField_accessStaticField

(JNIEnv *, jclass);

#ifdef __cplusplus

}

#endif

#endif

以上代码是程序入口类AccessField.class为native方法生成的本地代码函数原型头文件

// AccessField.c

#include "com_study_jnilearn_AccessField.h"

JNIEXPORTvoidJNICALL Java_com_study_jnilearn_AccessField_accessInstanceField

(JNIEnv *env, jclass cls, jobject obj)

{

jclass clazz;

jfieldID fid;

jstring j_str;

jstring j_newStr;

constchar*c_str = NULL;

// 1.获取AccessField类的Class引用

clazz = (*env)->GetObjectClass(env,obj);

if(clazz == NULL) {

return;

}

// 2. 获取AccessField类实例变量str的属性ID

fid = (*env)->GetFieldID(env,clazz,"str","Ljava/lang/String;");

if(clazz == NULL) {

return;

}

// 3. 获取实例变量str的值

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

// 4. 将unicode编码的java字符串转换成C风格字符串

c_str = (*env)->GetStringUTFChars(env,j_str,NULL);

if(c_str == NULL) {

return;

}

printf("In C--->ClassField.str = %s\n", c_str);

(*env)->ReleaseStringUTFChars(env, j_str, c_str);

// 5. 修改实例变量str的值

j_newStr = (*env)->NewStringUTF(env,"This is C String");

if(j_newStr == NULL) {

return;

}

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

// 6.删除局部引用

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

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

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

}

JNIEXPORTvoidJNICALL Java_com_study_jnilearn_AccessField_accessStaticField

(JNIEnv *env, jclass cls)

{

jclass clazz;

jfieldID fid;

jint num;

//1.获取ClassField类的Class引用

clazz = (*env)->FindClass(env,"com/study/jnilearn/ClassField");

if(clazz == NULL) {// 错误处理

return;

}

//2.获取ClassField类静态变量num的属性ID

fid = (*env)->GetStaticFieldID(env, clazz,"num","I");

if(fid == NULL) {

return;

}

// 3.获取静态变量num的值

num = (*env)->GetStaticIntField(env,clazz,fid);

printf("In C--->ClassField.num = %d\n", num);

// 4.修改静态变量num的值

(*env)->SetStaticIntField(env, clazz, fid, 80);

// 删除属部引用

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

}

// AccessField.c

#include "com_study_jnilearn_AccessField.h"

JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessField_accessInstanceField

(JNIEnv *env, jclass cls, jobject obj)

{

jclass clazz;

jfieldID fid;

jstring j_str;

jstring j_newStr;

const char *c_str = NULL;

// 1.获取AccessField类的Class引用

clazz = (*env)->GetObjectClass(env,obj);

if (clazz == NULL) {

return;

}

// 2. 获取AccessField类实例变量str的属性ID

fid = (*env)->GetFieldID(env,clazz,"str", "Ljava/lang/String;");

if (clazz == NULL) {

return;

}

// 3. 获取实例变量str的值

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

// 4. 将unicode编码的java字符串转换成C风格字符串

c_str = (*env)->GetStringUTFChars(env,j_str,NULL);

if (c_str == NULL) {

return;

}

printf("In C--->ClassField.str = %s\n", c_str);

(*env)->ReleaseStringUTFChars(env, j_str, c_str);

// 5. 修改实例变量str的值

j_newStr = (*env)->NewStringUTF(env, "This is C String");

if (j_newStr == NULL) {

return;

}

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

// 6.删除局部引用

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

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

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

}

JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessField_accessStaticField

(JNIEnv *env, jclass cls)

{

jclass clazz;

jfieldID fid;

jint num;

//1.获取ClassField类的Class引用

clazz = (*env)->FindClass(env,"com/study/jnilearn/ClassField");

if (clazz == NULL) { // 错误处理

return;

}

//2.获取ClassField类静态变量num的属性ID

fid = (*env)->GetStaticFieldID(env, clazz, "num", "I");

if (fid == NULL) {

return;

}

// 3.获取静态变量num的值

num = (*env)->GetStaticIntField(env,clazz,fid);

printf("In C--->ClassField.num = %d\n", num);

// 4.修改静态变量num的值

(*env)->SetStaticIntField(env, clazz, fid, 80);

// 删除属部引用

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

}

以上代码是对头文件中函数原型的实现。

运行程序,输出结果如下:

a4c26d1e5885305701be709a3d33442f.png

代码解析:

一、访问实例变量

在main方法中,通过调用accessInstanceField()方法来调用本地函数Java_com_study_jnilearn_AccessField_accessInstanceField,定位到函数32行:

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

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

该函数就是用于获取ClassField对象中num的值。下面是函数的原型:

jobject (JNICALL *GetObjectField) (JNIEnv *env, jobject obj, jfieldID fieldID);

jobject (JNICALL *GetObjectField) (JNIEnv *env, jobject obj, jfieldID fieldID);

因为实例变量str是String类型,属于引用类型。在JNI中获取引用类型字段的值,调用GetObjectField函数获取。同样的,获取其它类型字段值的函数还有GetIntField,GetFloatField,GetDoubleField,GetBooleanField等。这些函数有一个共同点,函数参数都是一样的,只是函数名不同,我们只需学习其中一个函数如何调用即可,依次类推,就自然知道其它函数的使用方法。

GetObjectField函数接受3个参数,env是JNI函数表指针,obj是实例变量所属的对象,fieldID是变量的ID(也称为属性描述符或签名),和上一章中方法描述符是同一个意思。env和obj参数从Java_com_study_jnilearn_AccessField_accessInstanceField函数形参列表中可以得到,那fieldID怎么获取呢?了解Java反射的童鞋应该知道,在Java中任何一个类的.class字节码文件被加载到内存中之后,该class子节码文件统一使用Class类来表示该类的一个引用(相当于Java中所有类的基类是Object一样)。然后就可以从该类的Class引用中动态的获取类中的任意方法和属性。注意:Class类在Java

SDK继承体系中是一个独立的类,没有继承自Object。请看下面的例子,通过Java反射机制,动态的获取一个类的私有实例变量的值:

publicstaticvoidmain(String[] args)throwsException {

ClassField obj =newClassField();

obj.setStr("YangXin");

// 获取ClassField字节码对象的Class引用

Class

分享:

a4c26d1e5885305701be709a3d33442f.png喜欢

0

a4c26d1e5885305701be709a3d33442f.png赠金笔

加载中,请稍候......

评论加载中,请稍候...

发评论

登录名: 密码: 找回密码 注册记住登录状态

昵   称:

评论并转载此博文

a4c26d1e5885305701be709a3d33442f.png

发评论

以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值