JNI全攻略之六――操作Java對(duì)象的屬性 江蘇 無錫 繆小東 本篇講述如何在本地方法中操作java對(duì)象的屬性,。該屬性可以是實(shí)例變量也可以是類變量。下面是兩個(gè)例子,。 一,、 操作屬性 類的屬性包含兩種:實(shí)例變量和類變量,。下面就分別講解吧!(很多讀者都說以前的關(guān)于JNI文章講解太少了,,不太能看懂,,下面的文章我將比較詳細(xì)地講解。) 1.1實(shí)例變量 下面是一個(gè)包含一個(gè)本地方法的類,,該類有基本數(shù)據(jù)類型型的屬性,、String類型的屬性以及自定義類型的屬性,幾乎可以包含我們所有類型的實(shí)例屬性,。 // InstanceFieldAccess.java public class InstanceFieldAccess { //下面是3種類型的實(shí)例變量 private String str; private int attr ; private Employee emp ; private native void accessField(); //訪問以上屬性的本地方法 public static void main(String args[]) { //main方法,,不用說了吧! InstanceFieldAccess c = new InstanceFieldAccess(); //實(shí)例化該對(duì)象 c.str = "abc"; //不是private的,,怎么可以使用?。肯胂氚?!為什么 c.attr = 5; //private是內(nèi)外不能訪問,,這可是在類的內(nèi)部哦! c.emp=new Employee("master24",28); //創(chuàng)建一個(gè)引用類型的屬性 c.accessField(); //調(diào)用該本地方法,,實(shí)現(xiàn)在后面 System.out.println("In Java:"); //在java中輸出 System.out.println(" c.str = "" + c.str + " ""); //看看在JNI中操作的屬性,, //在java中是否有“后遺癥” } static { //在類構(gòu)造前,加載動(dòng)態(tài)鏈接庫 System.loadLibrary("InstanceFieldAccess"); } } class Employee{ //一個(gè)輔助類,,我們會(huì)用它做一個(gè)復(fù)雜的調(diào)用 private String ; private int age =-1; Employee(){ } Employee(String n , int a ){ name = n ; age =a ; } public void setName(String n){ name = n ; } public void setAge(int a){ age =a ; } public String getName(){ return name ; } public int getAge(){ return age ; } } //InstanceFieldAccess.c 在你的VC中建立的C文件,,不會(huì)請(qǐng)參考第一篇 #include <stdio.h> #include <stdarg.h> #include <jni.h> JNIEXPORT void JNICALL Java_InstanceFieldAccess_accessField(JNIEnv *env, jobject obj){ //以下三段,不同色的分別演示操作String類型的屬性,、int類型的屬性、對(duì)象屬性 jfieldID fid; //存放屬性(field)的標(biāo)識(shí)符(ID),看到了吧,,一般稱fid jstring jstr; //JNI中的String const char *str; // jint int1 ; //JNI中的int jobject empobj ; //屬性Employee的實(shí)例 jclass empcls; //屬性Employee的類 jclass cls = (*env)->GetObjectClass(env, obj); //得到該對(duì)象的class,,第一步哦! printf("In C: n"); //本地輸出方法 fid = (*env)->GetFieldID(env, cls, "str","Ljava/lang/String;"); //得到屬性的標(biāo)識(shí)符 //第一個(gè)參數(shù)為env //第二個(gè)參數(shù)為上面第一步的class //第三個(gè)是InstanceFieldAccess.java // 中屬性的名稱 //第四個(gè)是方法的返回值,將Signature // 第二步哦,! //實(shí)例變量和類的變量使用不同方法 if (fid == NULL) { return; //沒有得到此fid就返回 } jstr = (*env)->GetObjectField(env, obj, fid); //得到實(shí)例的屬性,第三步哦,! //一般格式為Get <Type>Field //實(shí)例變量和類變量不同 str = (*env)->GetStringUTFChars(env, jstr, NULL); //操作String的方法 if (str == NULL) { return; } printf(" c.str = "%s " n", str); //輸出此String (*env)->ReleaseStringUTFChars(env, jstr, str); //釋放此String jstr = (*env)->NewStringUTF(env, "mater24"); //創(chuàng)建一個(gè)String if (jstr == NULL) { return; } (*env)->SetObjectField(env, obj, fid, jstr); //將此String賦值給此成員變量 //第二部分 fid = (*env)->GetFieldID(env, cls, "attr","I"); //得到類型為int屬性attr的ID if (fid == NULL) { return; } int1 = (*env)->GetIntField(env, obj, fid); //看到了吧,!Get<Type>Field if (int1 == NULL) { return; } printf(" c.attr = "%d " n", int1); //輸出此int printf(" c.attr = "%d " n", int1); //第三部分 fid = (*env)->GetFieldID(env, cls, "emp","LEmployee;");//得到類型為Employee屬性emp的ID if (fid == NULL) { return; } empobj = (*env)->GetObjectField(env, obj, fid); //同上,Get<Type>Field if (empobj== NULL) { return; } //此時(shí)我們得到一個(gè)Employee的實(shí)例 empcls = (*env)->GetObjectClass(env, empobj); //得到Employee的Class printf("In C: n Use Employee Instance !"); //在本地代碼中輸出 fid = (*env)->GetFieldID(env, empcls , "name","Ljava/lang/String;"); //繼續(xù)得到Employee的屬性的ID if (fid == NULL) { return; } //屬性類型為String,,名稱為name jstr = (*env)->GetObjectField(env, empobj, fid); //得到那么屬性的值 str = (*env)->GetStringUTFChars(env, jstr, NULL); //得到此String的拷貝 if (str == NULL) { return; } printf(" e.name = "%s " n", str); (*env)->ReleaseStringUTFChars(env, jstr, str); //釋放,,不過肯定少釋放一次!找找在哪里 } 操作類的實(shí)例屬性分為三步: 1. 得到類的類,。使用函數(shù): jclass GetObjectClass(JNIEnv *env, jobject obj); 2. 得到你要要的實(shí)例屬性的標(biāo)識(shí)符,。使用函數(shù): jfieldID GetFieldID(JNIEnv *env, jclass clazz,const char *name, const char *sig); 3. 得到該屬性對(duì)應(yīng)的值。使用函數(shù) <NativeType> Get<Type>Field(JNIEnv *env,jobject obj, jfieldID fieldID); 一定要看好了參數(shù)哦,! 1.2 靜態(tài)成員變量 這個(gè)例子相對(duì)比較簡(jiǎn)單點(diǎn),!一個(gè)包含本地方法的類!主要包含兩個(gè)靜態(tài)的屬性,,一個(gè)為String類型,,另外一個(gè)為自定義Manager類型! public class StaticFieldAccess { private static String str; private static Manager mgr = new Manager() ; private native void accessStaticField(); //本地方法 public static void main(String args[]) { StaticFieldAccess sfa = new StaticFieldAccess(); //創(chuàng)建類的實(shí)例 StaticFieldAccess.str = "I'm Static!"; //給類的靜態(tài)屬性賦值 sfa.accessStaticField(); //調(diào)用本地方法 System.out.println("In Java:"); //java中輸出 System.out.println(" StaticFieldAccess.str = " + str); } static { System.loadLibrary("StaticFieldAccess"); } } class Manager{ //簡(jiǎn)單的包含靜態(tài)屬性的類 static String company="Microsoft!"; } JNI的實(shí)現(xiàn),。主要演示:1.訪問類的String類型的靜態(tài)屬性str,;2.訪問類的Manager類型的屬性mgr,接著訪問該實(shí)例的String類型的靜態(tài)屬性company,??雌饋磔^復(fù)雜,好好理解就很很簡(jiǎn)單了,! #include <jni.h> JNIEXPORT void JNICALL Java_StaticFieldAccess_accessStaticField (JNIEnv *env , jobject obj){ //一系列訪問類的靜態(tài)屬性用到的中間變量 jclass cls ; //該類的類 jfieldID fid ; //方法的標(biāo)識(shí)符 jobject str ; //String類型屬性的對(duì)象 const char *jstr ; //JNI中的String jstring newstr ; //JNI中新創(chuàng)建的String //相應(yīng)地以下是訪問類的Manager類型靜態(tài)屬性(此時(shí)得到Manager-mgr) //的靜態(tài)的String類型的屬性的中間變量(此時(shí)得到company) jclass mgrcls ; jobject mgrobj ; jfieldID mgrfid ; jfieldID cpyfid ; jobject mgrstr ; const char *cpystr; cls = (*env)->GetObjectClass(env, obj); printf("In C: n"); fid = (*env)->GetStaticFieldID(env, cls, "str", "Ljava/lang/String;"); if (fid == NULL) { return; } str= (*env)->GetStaticObjectField(env, cls, fid); jstr = (*env)->GetStringUTFChars(env, str, NULL); if (jstr == NULL) { return; } printf(" StaticFieldAccess.str = %s n", jstr); (*env)->ReleaseStringUTFChars(env, str, jstr); //釋放此String newstr = (*env)->NewStringUTF(env, "XXXXXXXXXXXXX"); if (newstr == NULL) { return; } (*env)->SetStaticObjectField(env, cls, fid, newstr); printf("In C: n Use Manager Class !"); mgrfid = (*env)->GetStaticFieldID(env, cls, "mgr", "LManager;"); if (mgrfid == NULL) { return; } mgrobj = (*env)->GetStaticObjectField(env, cls, mgrfid); //cls mgrcls= (*env)->GetObjectClass(env, mgrobj); cpyfid = (*env)->GetStaticFieldID(env, mgrcls, "company", "Ljava/lang/String;"); if (cpyfid == NULL) { return; } mgrstr = (*env)->GetStaticObjectField(env, mgrcls, cpyfid);////////////' cpystr = (*env)->GetStringUTFChars(env, mgrstr, NULL); //得到此String的拷貝 if (cpystr == NULL) { return; } printf(" StaticFieldAccess.mgr.Company = %s n", cpystr); (*env)->ReleaseStringUTFChars(env, mgrstr, cpystr); //釋放此String } 以下是執(zhí)行結(jié)果,! In Java: StaticFieldAccess.str = XXXXXXXXXXXXX In C: StaticFieldAccess.str = I'm Static! In C: Use Manager Class ! StaticFieldAccess.mgr.Company = Microsoft! 操作類的實(shí)例屬性分為三步: 1. 得到類的類。使用函數(shù): jclass GetObjectClass(JNIEnv *env, jobject obj); 2. 得到你要要的實(shí)例屬性的標(biāo)識(shí)符,。使用函數(shù): jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz,const char *name, const char *sig); 3. 得到該屬性對(duì)應(yīng)的值,。使用函數(shù) <NativeType> GetStatic<Type>Field(JNIEnv *env,jclass cls , jfieldID fieldID); 一定要看好了參數(shù)哦! 以前都使用那個(gè)黑漆漆的貼圖,現(xiàn)在使用文字結(jié)果了,!怎么搞?。?/span> java StaticFieldAccess >1.txt 這樣你運(yùn)行StaticFieldAccess的結(jié)果就放到與你的類同目錄的文本文件1.txt中了,!有意思吧,! 1.3操作屬性的差異: 主要在第2、3步,。第二步GetFieldID 和GetStaticFieldID看到了吧,!參數(shù)的個(gè)數(shù)和意義相同!第三步Get<Type>Field和GetStatic<Type>Field名稱不同,,且第二個(gè)參數(shù),,實(shí)例屬性的為jobject,類屬性的為jclass,。和java中極其類似吧,!
|
|