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
jclass GetObjectClass(JNIEnv *env, jobject obj);
返回对象的类。
参数:
env:JNI 接口指针。
obj:Java 对象(不能为 NULL)。
返回值:
返回 Java 类对象。
GetFieldID
jfieldID GetFieldID(JNIEnv *env, jclass clazz,
const char *name, const char *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 例程
NativeType Get<type>Field(JNIEnv *env, jobject obj,
jfieldID fieldID);
该访问器例程系列返回对象的实例(非静态)域的值。要访问的域由通过调用 GetFieldID() 而得到的域 ID 指定。
Set<type>Field 例程
void Set<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID,
NativeType value);
NewStringUTF
jstring NewStringUTF(JNIEnv *env, const char *bytes);
利用 UTF-8 字符数组构造新 java.lang.String 对象。
参数:
env:JNI 接口指针。如果无法构造该字符串,则为 NULL。
bytes:指向 UTF-8 字符串的指针。
返回值:
Java 字符串对象。如果无法构造该字符串,则为 NULL。
ReleaseStringUTFChars
void ReleaseStringUTFChars(JNIEnv *env, jstring string,
const char *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 例程
void SetStatic<type>Field(JNIEnv *env, jclass clazz,
jfieldID fieldID, NativeType value);
该访问器例程系列设置对象的静态域的值。要访问的域由通过调用 GetStaticFieldID() 而得到的域 ID 指定。
GetStatic<type>Field 例程
NativeType GetStatic<type>Field(JNIEnv *env, jclass clazz,
jfieldID fieldID);
该访问器例程系列返回对象的静态域的值。要访问的域由通过调用 GetStaticFieldID() 而得到的域 ID 指定。
型。这个字符串被称为JNI field descriptor(字段描述符)。
字符串的内容由字段被声明的类型决定。例如,使用“I”来表示一个int类型的字段,“F”
来表示一个float类型的字段,“D”来表示一个double 类型的字段,“Z”来表示一个 boolean
类型的字段等等。
像java.lang.String这样的引用类型的描述符都是以L开头,后面跟着一个JNI类描述符,以
分号结尾。一个JAVA 类的全名中的包名分隔符“.”被转化成“/”。因此,对于一个字段类
型的字段来说,它的描述符是“Ljava/lang/String”。 数组的描述符中包含“]”字符