<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                在上一章中我們學習到了如何在本地代碼中訪問任意Java類中的靜態方法和實例方法,本章我們也通過一個示例來學習Java中的實例變量和靜態變量,在本地代碼中如何來訪問和修改。靜態變量也稱為類變量(屬性),在所有實例對象中共享同一份數據,可以直接通過【類名.變量名】來訪問。實例變量也稱為成員變量(屬性),每個實例都擁有一份實例變量數據的拷貝,它們之間修改后的數據互不影響。下面看一個例子: ~~~ package com.study.jnilearn; /** * C/C++訪問類的實例變量和靜態變量 * @author yangxin */ 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實例作為形參,用于訪問該對象中的實例變量。 ~~~ package com.study.jnilearn; /** * ClassField.java * 用于本地代碼訪問和修改該類的屬性 * @author yangxin * */ 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。這兩個變量會被本地代碼訪問和修改。 ~~~ /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_study_jnilearn_AccessField */ #ifndef _Included_com_study_jnilearn_AccessField #define _Included_com_study_jnilearn_AccessField #ifdef __cplusplus extern "C" { #endif /* * Class: com_study_jnilearn_AccessField * Method: accessInstanceField * Signature: (Lcom/study/jnilearn/ClassField;)V */ JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessField_accessInstanceField (JNIEnv *, jclass, jobject); /* * Class: com_study_jnilearn_AccessField * Method: accessStaticField * Signature: ()V */ 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" /* * Class: com_study_jnilearn_AccessField * Method: accessInstanceField * Signature: ()V */ 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); } /* * Class: com_study_jnilearn_AccessField * Method: accessStaticField * Signature: ()V */ 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); } ~~~ 以上代碼是對頭文件中函數原型的實現。 *** *** **運行程序,輸出結果如下:** ![](https://box.kancloud.cn/2016-02-16_56c2c9473b468.jpg) **代碼解析:** **一、訪問實例變量** 在main方法中,通過調用accessInstanceField()方法來調用本地函數Java_com_study_jnilearn_AccessField_accessInstanceField,定位到函數32行: ~~~ j_str = (jstring)(*env)->GetObjectField(env,obj,fid); ~~~ 該函數就是用于獲取ClassField對象中num的值。下面是函數的原型: ~~~ 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反射機制,動態的獲取一個類的私有實例變量的值: ~~~ public static void main(String[] args) throws Exception { ClassField obj = new ClassField(); obj.setStr("YangXin"); // 獲取ClassField字節碼對象的Class引用 Class<?> clazz = obj.getClass(); // 獲取str屬性 Field field = clazz.getDeclaredField("str"); // 取消權限檢查,因為Java語法規定,非public屬性是無法在外部訪問的 field.setAccessible(true); // 獲取obj對象中的str屬性的值 String str = (String)field.get(obj); System.out.println("str = " + str); } ~~~ 運行程序后,輸出結果當然是打印出str屬性的值“YangXin”。所以我們在本地代碼中調用JNI函數訪問Java對象中某一個屬性的時候,首先第一步就是要獲取該對象的Class引用,然后在Class中查找需要訪問的字段ID,最后調用JNI函數的GetXXXField系列函數,獲取字段(屬性)的值。上例中,首先調用GetObjectClass函數獲取ClassField的Class引用: ~~~ clazz = (*env)->GetObjectClass(env,obj); ~~~ 然后調用GetFieldID函數從Class引用中獲取字段的ID(str是字段名,Ljava/lang/String;是字段的類型) ~~~ fid = (*env)->GetFieldID(env,clazz,"str", "Ljava/lang/String;"); ~~~ 最后調用GetObjectField函數,傳入實例對象和字段ID,獲取屬性的值 ~~~ j_str = (jstring)(*env)->GetObjectField(env,obj,fid); ~~~ 調用SetXXXField系列函數,可以修改實例屬性的值,最后一個參數為屬性的值。引用類型全部調用SetObjectField函數,基本類型調用SetIntField、SetDoubleField、SetBooleanField等 ~~~ (*env)->SetObjectField(env, obj, fid, j_newStr); ~~~ **二、訪問靜態變量** 訪問靜態變量和實例變量不同的是,獲取字段ID使用GetStaticFieldID,獲取和修改字段的值使用Get/SetStaticXXXField系列函數,比如上例中獲取和修改靜態變量num: ~~~ // 3.獲取靜態變量num的值 num = (*env)->GetStaticIntField(env,clazz,fid); // 4.修改靜態變量num的值 (*env)->SetStaticIntField(env, clazz, fid, 80); ~~~ **總結:** 1、由于JNI函數是直接操作JVM中的數據結構,不受Java訪問修飾符的限制。即,在本地代碼中可以調用JNI函數可以訪問Java對象中的非public屬性和方法 **2、訪問和修改實例變量操作步聚:** ?1>、調用GetObjectClass函數獲取實例對象的Class引用 ?2>、調用GetFieldID函數獲取Class引用中某個實例變量的ID ?3>、調用GetXXXField函數獲取變量的值,需要傳入實例變量所屬對象和變量ID ?4>、調用SetXXXField函數修改變量的值,需要傳入實例變量所屬對象、變量ID和變量的值 **3、訪問和修改靜態變量操作步聚:** ?1>、調用FindClass函數獲取類的Class引用 ?2>、調用GetStaticFieldID函數獲取Class引用中某個靜態變量ID ?3>、調用GetStaticXXXField函數獲取靜態變量的值,需要傳入變量所屬Class的引用和變量ID ?4>、調用SetStaticXXXField函數設置靜態變量的值,需要傳入變量所屬Class的引用、變量ID和變量的值 示例代碼下載地址:[https://code.csdn.net/xyang81/jnilearn](https://code.csdn.net/xyang81/jnilearn)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看