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