`
duoerbasilu
  • 浏览: 1482637 次
文章分类
社区版块
存档分类
最新评论

android NDK 入门之在JNI中修改java中对象的成员变量的值

 
阅读更多
android NDK 入门之在JNI中修改java中对象的成员变量的值
如题:测试在JNI中修改java代码中成员变量的值

JavaBean类编写如下
package com.xl.qiu;

public class StepByStepInstance {
public native void changeStepInstanceString();

public StepByStepInstance(String str1)
{
this.str1 = str1;
}

private String str1;

public String getStr1() {
return str1;
}

public void setStr1(String str1) {
this.str1 = str1;
}


}

调用处Java代码如下:
StepByStepInstance step = new StepByStepInstance("step");

step.changeStepInstanceString();


javah 工具生成.h头文件如下:

#include <jni.h>
/* Header for class com_xl_qiu_StepByStepInstance */

#ifndef _Included_com_xl_qiu_StepByStepInstance
#define _Included_com_xl_qiu_StepByStepInstance
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_xl_qiu_StepByStepInstance
* Method: changeStepInstanceString
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_xl_qiu_StepByStepInstance_changeStepInstanceString
(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

编写c语言代码如下:

JNIEXPORT void JNICALL Java_com_xl_qiu_StepByStepInstance_changeStepInstanceString(JNIEnv *env, jobject this) {
jfieldID fid;
jstring jstr;
const char *str;

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

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

if (fid == NULL)
return;

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

if (str == NULL)
return;

__android_log_print(ANDROID_LOG_INFO, "JNI", "In C Str:%s, Change in StepByStepInstance.java", str);

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

jstr = (*env)->NewStringUTF(env, "New String Given By C, Change field int StepByStepInstance.java");

if (jstr == NULL)
return;

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

}


简单解释一下JNI代码中几个调用的函数:

GetObjectClass

jclassGetObjectClass(JNIEnv*env,jobjectobj);

返回对象的类。

参数:

env:JNI接口指针。

obj:Java对象(不能为NULL)。

返回值:

返回Java类对象。



GetFieldID

jfieldIDGetFieldID(JNIEnv*env,jclassclazz,
constchar*name,constchar*sig);

返回类的实例(非静态)域的域ID。该域由其名称及签名指定。访问器函数的Get<type>Field及Set<type>Field系列使用域ID检索对象域。

GetFieldID()将未初始化的类初始化。

GetFieldID()不能用于获取数组的长度域。应使用GetArrayLength()。

参数:

env:JNI接口指针。

clazz:Java类对象。

name:0终结的UTF-8字符串中的域名。

sig:0终结的UTF-8字符串中的域签名。

返回值:

域ID。如果操作失败,则返回NULL。


Get<type>Field例程

NativeTypeGet<type>Field(JNIEnv*env,jobjectobj,
jfieldIDfieldID);

该访问器例程系列返回对象的实例(非静态)域的值。要访问的域由通过调用GetFieldID()而得到的域ID指定。


Set<type>Field例程

voidSet<type>Field(JNIEnv*env,jobjectobj,jfieldIDfieldID,
NativeTypevalue);



NewStringUTF

jstringNewStringUTF(JNIEnv*env,constchar*bytes);

利用UTF-8字符数组构造新java.lang.String对象。

参数:

env:JNI接口指针。如果无法构造该字符串,则为NULL。

bytes:指向UTF-8字符串的指针。

返回值:

Java字符串对象。如果无法构造该字符串,则为NULL。



ReleaseStringUTFChars

voidReleaseStringUTFChars(JNIEnv*env,jstringstring,
constchar*utf);

通知虚拟机平台相关代码无需再访问utf。utf参数是一个指针,可利用GetStringUTFChars()从string获得。

参数:

env:JNI接口指针。

string:Java字符串对象。

utf:指向UTF-8字符串的指针。




如上介绍了如何修改类成员变量(非静态,下面继续介绍如何修改静态类成员变量):

同样是StepByStepInstance类
我们添加类静态成员public static int static_i;
同样添加一个本地方法用来JNI修改static_i;
public native void changeStaticField();


.h文件中增加了方法声明:
JNIEXPORT void JNICALL Java_com_xl_qiu_StepByStepInstance_changeStaticField
(JNIEnv *, jobject);



c语言代码实现如下:

JNIEXPORT void JNICALL
Java_com_xl_qiu_StepByStepInstance_changeStaticField(
JNIEnv *env,
jobject this)
{
jfieldID fid;
jint si;

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

fid = (*env)->GetStaticFieldID(env, cls, "static_i", "I");
if (fid == NULL)
return;

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

__android_log_print(ANDROID_LOG_INFO, "JNI", "In C Str:%d, given by StepByStepInstance.java", si);

(*env)->SetStaticIntField(env, cls, fid, ++si);
}


JNI函数介绍:

SetStatic<type>Field例程

voidSetStatic<type>Field(JNIEnv*env,jclassclazz,
jfieldIDfieldID,NativeTypevalue);

该访问器例程系列设置对象的静态域的值。要访问的域由通过调用GetStaticFieldID()而得到的域ID指定。

GetStatic<type>Field例程

NativeTypeGetStatic<type>Field(JNIEnv*env,jclassclazz,
jfieldIDfieldID);

该访问器例程系列返回对象的静态域的值。要访问的域由通过调用GetStaticFieldID()而得到的域ID指定。




上述JNI代码中用到了字段描述符:
一个特殊的 C字符串“Ljava/lang/String”来代表一个JVM 中的字段类
型。这个字符串被称为JNI field descriptor(字段描述符)。
字符串的内容由字段被声明的类型决定。例如,使用“I”来表示一个int类型的字段,“F”
来表示一个float类型的字段,“D”来表示一个double 类型的字段,“Z”来表示一个 boolean
类型的字段等等。
像java.lang.String这样的引用类型的描述符都是以L开头,后面跟着一个JNI类描述符,以
分号结尾。一个JAVA 类的全名中的包名分隔符“.”被转化成“/”。因此,对于一个字段类
型的字段来说,它的描述符是“Ljava/lang/String”。 数组的描述符中包含“]”字符


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics