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);
}
以上代碼是對頭文件中函數原型的實現。
運行程序,輸出結果如下:
代碼解析:
一、訪問實例變量
在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
分享:
喜歡
0
贈金筆
加載中,請稍候......
評論加載中,請稍候...
發評論
登錄名: 密碼: 找回密碼 注冊記住登錄狀態
昵???稱:
評論并轉載此博文
發評論
以上網友發言只代表其個人觀點,不代表新浪網的觀點或立場。
總結
以上是生活随笔為你收集整理的jni java共享变量_JNI/NDK开发指南(七)——C/C++访问Java实例变量和静态变量 .的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java实现大数乘法_java实现大数加
- 下一篇: java mybatis拦截配置_Spr