jni java共享变量_JNI/NDK开发指南(七)——C/C++访问Java实例变量和静态变量 .
在上一章中我們學(xué)習(xí)到了如何在本地代碼中訪問(wèn)任意Java類中的靜態(tài)方法和實(shí)例方法,本章我們也通過(guò)一個(gè)示例來(lái)學(xué)習(xí)Java中的實(shí)例變量和靜態(tài)變量,在本地代碼中如何來(lái)訪問(wèn)和修改。靜態(tài)變量也稱為類變量(屬性),在所有實(shí)例對(duì)象中共享同一份數(shù)據(jù),可以直接通過(guò)【類名.變量名】來(lái)訪問(wèn)。實(shí)例變量也稱為成員變量(屬性),每個(gè)實(shí)例都擁有一份實(shí)例變量數(shù)據(jù)的拷貝,它們之間修改后的數(shù)據(jù)互不影響。下面看一個(gè)例子:
packagecom.study.jnilearn;
publicclassAccessField?{
privatenativestaticvoidaccessInstanceField(ClassField?obj);
privatenativestaticvoidaccessStaticField();
publicstaticvoidmain(String[]?args)?{
ClassField?obj?=newClassField();
obj.setNum(10);
obj.setStr("Hello");
//?本地代碼訪問(wèn)和修改ClassField為中的靜態(tài)屬性num
accessStaticField();
accessInstanceField(obj);
//?輸出本地代碼修改過(guò)后的值
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");
// 本地代碼訪問(wèn)和修改ClassField為中的靜態(tài)屬性num
accessStaticField();
accessInstanceField(obj);
// 輸出本地代碼修改過(guò)后的值
System.out.println("In Java--->ClassField.num = " + obj.getNum());
System.out.println("In Java--->ClassField.str = " + obj.getStr());
}
static {
System.loadLibrary("AccessField");
}
}
AccessField是程序的入口類,定義了兩個(gè)native方法:accessInstanceField和accessStaticField,分別用于演示在本地代碼中訪問(wèn)Java類中的實(shí)例變量和靜態(tài)變量。其中accessInstaceField方法訪問(wèn)的是類的實(shí)例變量,所以該方法需要一個(gè)ClassField實(shí)例作為形參,用于訪問(wèn)該對(duì)象中的實(shí)例變量。
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;
}
}
在本例中沒(méi)有將實(shí)例變量和靜態(tài)變量定義在程序入口類中,新建了一個(gè)ClassField的類來(lái)定義類的屬性,目的是為了加深在C/C++代碼中可以訪問(wèn)任意Java類中的屬性。在這個(gè)類中定義了一個(gè)int類型的實(shí)例變量num,和一個(gè)java.lang.String類型的靜態(tài)變量str。這兩個(gè)變量會(huì)被本地代碼訪問(wèn)和修改。
#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方法生成的本地代碼函數(shù)原型頭文件
//?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類實(shí)例變量str的屬性ID
fid?=?(*env)->GetFieldID(env,clazz,"str","Ljava/lang/String;");
if(clazz?==?NULL)?{
return;
}
//?3.?獲取實(shí)例變量str的值
j_str?=?(jstring)(*env)->GetObjectField(env,obj,fid);
//?4.?將unicode編碼的java字符串轉(zhuǎn)換成C風(fēng)格字符串
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.?修改實(shí)例變量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)?{//?錯(cuò)誤處理
return;
}
//2.獲取ClassField類靜態(tài)變量num的屬性ID
fid?=?(*env)->GetStaticFieldID(env,?clazz,"num","I");
if(fid?==?NULL)?{
return;
}
//?3.獲取靜態(tài)變量num的值
num?=?(*env)->GetStaticIntField(env,clazz,fid);
printf("In?C--->ClassField.num?=?%d\n",?num);
//?4.修改靜態(tài)變量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類實(shí)例變量str的屬性ID
fid = (*env)->GetFieldID(env,clazz,"str", "Ljava/lang/String;");
if (clazz == NULL) {
return;
}
// 3. 獲取實(shí)例變量str的值
j_str = (jstring)(*env)->GetObjectField(env,obj,fid);
// 4. 將unicode編碼的java字符串轉(zhuǎn)換成C風(fēng)格字符串
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. 修改實(shí)例變量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) { // 錯(cuò)誤處理
return;
}
//2.獲取ClassField類靜態(tài)變量num的屬性ID
fid = (*env)->GetStaticFieldID(env, clazz, "num", "I");
if (fid == NULL) {
return;
}
// 3.獲取靜態(tài)變量num的值
num = (*env)->GetStaticIntField(env,clazz,fid);
printf("In C--->ClassField.num = %d\n", num);
// 4.修改靜態(tài)變量num的值
(*env)->SetStaticIntField(env, clazz, fid, 80);
// 刪除屬部引用
(*env)->DeleteLocalRef(env,clazz);
}
以上代碼是對(duì)頭文件中函數(shù)原型的實(shí)現(xiàn)。
運(yùn)行程序,輸出結(jié)果如下:
代碼解析:
一、訪問(wèn)實(shí)例變量
在main方法中,通過(guò)調(diào)用accessInstanceField()方法來(lái)調(diào)用本地函數(shù)Java_com_study_jnilearn_AccessField_accessInstanceField,定位到函數(shù)32行:
j_str?=?(jstring)(*env)->GetObjectField(env,obj,fid);
j_str = (jstring)(*env)->GetObjectField(env,obj,fid);
該函數(shù)就是用于獲取ClassField對(duì)象中num的值。下面是函數(shù)的原型:
jobject?(JNICALL?*GetObjectField)?(JNIEnv?*env,?jobject?obj,?jfieldID?fieldID);
jobject (JNICALL *GetObjectField) (JNIEnv *env, jobject obj, jfieldID fieldID);
因?yàn)閷?shí)例變量str是String類型,屬于引用類型。在JNI中獲取引用類型字段的值,調(diào)用GetObjectField函數(shù)獲取。同樣的,獲取其它類型字段值的函數(shù)還有GetIntField,GetFloatField,GetDoubleField,GetBooleanField等。這些函數(shù)有一個(gè)共同點(diǎn),函數(shù)參數(shù)都是一樣的,只是函數(shù)名不同,我們只需學(xué)習(xí)其中一個(gè)函數(shù)如何調(diào)用即可,依次類推,就自然知道其它函數(shù)的使用方法。
GetObjectField函數(shù)接受3個(gè)參數(shù),env是JNI函數(shù)表指針,obj是實(shí)例變量所屬的對(duì)象,fieldID是變量的ID(也稱為屬性描述符或簽名),和上一章中方法描述符是同一個(gè)意思。env和obj參數(shù)從Java_com_study_jnilearn_AccessField_accessInstanceField函數(shù)形參列表中可以得到,那fieldID怎么獲取呢?了解Java反射的童鞋應(yīng)該知道,在Java中任何一個(gè)類的.class字節(jié)碼文件被加載到內(nèi)存中之后,該class子節(jié)碼文件統(tǒng)一使用Class類來(lái)表示該類的一個(gè)引用(相當(dāng)于Java中所有類的基類是Object一樣)。然后就可以從該類的Class引用中動(dòng)態(tài)的獲取類中的任意方法和屬性。注意:Class類在Java
SDK繼承體系中是一個(gè)獨(dú)立的類,沒(méi)有繼承自O(shè)bject。請(qǐng)看下面的例子,通過(guò)Java反射機(jī)制,動(dòng)態(tài)的獲取一個(gè)類的私有實(shí)例變量的值:
publicstaticvoidmain(String[]?args)throwsException?{
ClassField?obj?=newClassField();
obj.setStr("YangXin");
//?獲取ClassField字節(jié)碼對(duì)象的Class引用
Class
分享:
喜歡
0
贈(zèng)金筆
加載中,請(qǐng)稍候......
評(píng)論加載中,請(qǐng)稍候...
發(fā)評(píng)論
登錄名: 密碼: 找回密碼 注冊(cè)記住登錄狀態(tài)
昵???稱:
評(píng)論并轉(zhuǎn)載此博文
發(fā)評(píng)論
以上網(wǎng)友發(fā)言只代表其個(gè)人觀點(diǎn),不代表新浪網(wǎng)的觀點(diǎn)或立場(chǎng)。
總結(jié)
以上是生活随笔為你收集整理的jni java共享变量_JNI/NDK开发指南(七)——C/C++访问Java实例变量和静态变量 .的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java实现大数乘法_java实现大数加
- 下一篇: java mybatis拦截配置_Spr