jni.h頭文件詳解二


作者:左少華
博客:http://blog.csdn.net/shaohuazuo/article/details/42932813
轉載請注明出處:http://blog.csdn.net/shaohuazuo

一:struct JNINativeInterface_{}

  結構體的作用:它有點像我們char字符驅動的 file_ops結構體,它定義各種函數對在(jni.h頭文件詳解一)中定義的各種數據的操作函數集體.

二:它包含那些針對Java中類和對象的相關操作呢如下圖.

  

三:下面我們講詳細介紹14個部分方法的用法和解析

3.1.版本信息操作函數.

一.GetVersion

 jint (JNICALL *GetVersion)(JNIEnv *env)

 --模塊信息:該模塊主要針對的JNI接口的版本信息操作函數.


函數原型:jint (JNICALL *GetVersion)(JNIEnv *env)

 描 述:它用來返回jni的版本信息.version = (*env)->GetVersion(env);   
     我們通過這個方法獲取版本信息.並通過回調java的getVersion()方法顯示版本號. 
 參 數:這個JNIEnv是JNI的運行環境.這個環境中包含了上圖的14大塊的操作函數等等.
 返回值:返回一個0-65535大小的數.他是一個16位的正整數.高八位是主版本號.低八位是次版本號.
  例 程:

 --1.1 函數使用Demo流程介紹.

     通過Java對象的構造方法,把當前對象傳遞到C中.C獲取到該對象之后,保存Java對象的引用,並獲取相應的方法等.

     獲取該對象之后,C會調用獲取JNI版本的函數.獲取版本號,並調用Java層的getVersion()函數,將版本號顯示出來.如圖:

  

   

 

 --1.2 代碼
[cpp]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. package com.octopus.test03;  
  2. import android.os.Bundle;  
  3. import android.app.Activity;  
  4. import android.graphics.Color;  
  5. import android.view.Menu;  
  6. import android.view.View;  
  7. import android.view.View.OnClickListener;  
  8. import android.widget.Button;  
  9. import android.widget.LinearLayout;  
  10. import android.widget.TextView;  
  11.   
  12. public class Act1 extends Activity implements OnClickListener {  
  13.     private final int WC = LinearLayout.LayoutParams.WRAP_CONTENT;  
  14.     private final int FP = LinearLayout.LayoutParams.FILL_PARENT;  
  15.     private Button btn, btn3;  
  16.     public static Act1 ref;  
  17.     public TextView tv;  
  18.   
  19.     @Override  
  20.     protected void onCreate(Bundle icicle) {  
  21.         super.onCreate(icicle);  
  22.         ref = this;  
  23.         LinearLayout layout = new LinearLayout(this);  
  24.         layout.setOrientation(LinearLayout.VERTICAL);  
  25.         btn = new Button(this);  
  26.         btn.setId(101);  
  27.         btn.setText("run(Adder)");  
  28.         btn.setBackgroundResource(R.drawable.ic_launcher);  
  29.         btn.setOnClickListener(this);  
  30.         LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(120, 50);  
  31.         param.topMargin = 10;  
  32.         layout.addView(btn, param);  
  33.         btn3 = new Button(this);  
  34.         btn3.setId(103);  
  35.         btn3.setText("exit");  
  36.         btn3.setBackgroundResource(R.drawable.ic_launcher);  
  37.         btn3.setOnClickListener(this);  
  38.         layout.addView(btn3, param);  
  39.         tv = new TextView(this);  
  40.         tv.setTextColor(Color.WHITE);  
  41.         tv.setText("");  
  42.         LinearLayout.LayoutParams param2 = new LinearLayout.LayoutParams(FP, WC);  
  43.         param2.topMargin = 10;  
  44.         layout.addView(tv, param2);  
  45.         setContentView(layout);  
  46.     }  
  47.   
  48.     public void onClick(View v) {  
  49.         if (v == btn) {  
  50.             int a = 1, b = 1;  
  51.             GetVersion adder = new GetVersion();  
  52.         } else if (v == btn3) {  
  53.             finish();  
  54.         }  
  55.     }  
  56.   
  57.     @Override  
  58.     public boolean onCreateOptionsMenu(Menu menu) {  
  59.         // Inflate the menu; this adds items to the action bar if it is present.  
  60.         getMenuInflater().inflate(R.menu.main, menu);  
  61.         return true;  
  62.     }  
  63.   
  64. }  
  65.      
  --1.3 Jni層代碼
[cpp]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. package com.octopus.test03;  
  2.   
  3. import java.lang.ref.WeakReference;  
  4.   
  5. import android.os.Handler;  
  6. import android.os.Message;  
  7.   
  8. public class GetVersion {  
  9.       
  10.     private static Handler h;  
  11.     static {  
  12.         System.loadLibrary("HelloNdk");  
  13.     }  
  14.   
  15.     public GetVersion() {  
  16.       
  17.         h = new Handler() {  
  18.             public void handleMessage(Message msg) {  
  19.                 Act1.ref.setTitle(msg.obj.toString());  
  20.             }  
  21.         };  
  22.         nativeSetup(new WeakReference<GetVersion>(this));  
  23.     }  
  24.       
  25.     private static void getVersion(Object version_ref, int what,int message)  
  26.     {  
  27.           
  28.         String obj1 = "Jni Version is : "+ message;  
  29.         Message m = h.obtainMessage(what, obj1);  
  30.         h.sendMessage(m);  
  31.     }  
  32.       
  33.     private native void nativeSetup(Object weak_this);  
  34.   
  35. }  
  --1.4 C 層代碼
[cpp]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1.  1 /* DO NOT EDIT THIS FILE - it is machine generated */  
  2.  2 #include "com_octopus_test03_GetVersion.h"  
  3.  3 /* Header for class com_octopus_test03_GetVersion */  
  4.  4   
  5.  5 /* 
  6.  6  * Class:     com_octopus_test03_GetVersion 
  7.  7  * Method:    nativeSetup 
  8.  8  * Signature: (Ljava/lang/Object;)V 
  9.  9  */  
  10. 10   
  11. 11 jclass mClass;  
  12. 12 jobject mObject;  
  13. 13 jmethodID mid;  
  14. 14   
  15. 15 JNIEXPORT void JNICALL Java_com_octopus_test03_GetVersion_nativeSetup  
  16. 16   (JNIEnv *env, jobject this, jobject weak_this)  
  17. 17 {  
  18. 18     jint version =0;  
  19. 19     jclass class = (*env)->GetObjectClass(env,this);  
  20. 20     mClass =  (jclass)(*env)->NewGlobalRef(env,class);  
  21. 21     mObject = (*env)->NewGlobalRef(env,weak_this);   
  22. 22     mid = (*env)->GetStaticMethodID(env, mClass,"getVersion","(Ljava/lang/Object;II)V");  
  23. 23       
  24. 24     version = (*env)->GetVersion(env);   //我們通過這個方法獲取版本信息.並通過回調java的getVersion()方法顯示版本號.   
  25. 25     (*env)->CallStaticVoidMethod(env,mClass,mid,mObject,1,version);  
  26. 26     return ;  
  27. 27 }                                                                                                                                                                                     
  28.                                                                                                                                                                                        
1.5.Android.mk文件如下:
[cpp]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. SRC_PATH_ROOT:=$(LOCAL_PATH)/../../src  
  2. LOCAL_PATH := $(call my-dir)    
  3. include $(CLEAR_VARS)  
  4. LOCAL_MODULE    := HelloNdk  
  5. LOCAL_SRC_FILES := com_octopus_test03_GetVersion.c  
  6. include $(BUILD_SHARED_LIBRARY)  
--1.6 測試當前JNI的版本為65542

 

.

轉載請說明出處:  http://blog.csdn.net/shaohuazuo/

.

 

 

3.2. 類模塊相關操作.

(DefineClass,FindClass)

 jclass (JNICALL *DefineClass)  (JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len);

 jclass (JNICALL *FindClass) (JNIEnv *env, const char *name);

 --模塊信息:這個模塊主要是C或者C++中如何獲取Java的Class類對象. 這個接口再Android上沒有得到支持.

一:DefineClass

 

函數原型:jclass (JNICALL *DefineClass)  (JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len);

 描 述: 從二進制的.class的數據緩沖區中加載類.

 參 數: env    java本地接口指針.

        name   需要加載類的簡短名稱.比如下載需要加載一個com/zuoshaohua/Test.java這個類,那么該名稱就是 Test

        loader 類加載器對象.該類用來加載java字節碼.class文件

        buf    這個是字節碼緩沖區數組.

        len    該數組的長度.

  返回值:

       返回一個jclass類型的結構體.他對應的是Java中的類相關信息.

  例 程:

   --1.1 相關的java背景知識說.可以參考http://blog.csdn.net/lovingprince/article/details/4317069博客,

         Java類加載器.也就是我們的loader參數的詳細介紹.

        在這里我們簡單的說說loader的作用.在Java語言中loader是一個將 .class文件加載到內存的一個類加載器.

   --1.2 例程的業務邏輯介紹:

        寫一個測試的java類.他用來輸出一個字符串..我們把他編譯成一個.class文件.然后使用DefineClass進行加載.

        並再Activity中輸出該字符串.

 

 

 

--1.3代碼  (注釋 界面代碼和上一個實例是一樣的.)

   

[java]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. package com.octopus.test03;  
  2.   
  3. import java.lang.ref.WeakReference;  
  4.   
  5. import android.os.Handler;  
  6. import android.os.Message;  
  7.   
  8. public class DefindClassTest {  
  9.     ClassLoader loader;  
  10.     private static Handler h;  
  11.     static {  
  12.         System.loadLibrary("HelloNdk");  
  13.     }  
  14.   
  15.     public DefindClassTest() {  
  16.       
  17.         h = new Handler() {  
  18.             public void handleMessage(Message msg) {  
  19.                 Act1.ref.setTitle(msg.obj.toString());  
  20.             }  
  21.         };  
  22.         loader = DefindClassTest.class.getClassLoader();  
  23.         if(loader==null){  
  24.             System.out.println("loader error\n");  
  25.         }  
  26.                 //將獲得的類加載器,傳入到C層.  
  27.                 nativeSetup(new WeakReference<ClassLoader>(loader));  
  28.          
  29.     }  
  30.       
  31.     private static void getVersion(Object version_ref, Object test, int what,int message)  
  32.     {  
  33.         String obj1 = "Jni Version is : "+ message+ "C Create obj is"+ test;  
  34.         Message m = h.obtainMessage(what, obj1);  
  35.         h.sendMessage(m);  
  36.     }  
  37.       
  38.     private native void nativeSetup(Object weak_this);  
  39.   
  40. }  

 

--1.4 jni中c端實現代碼
[cpp]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. /* DO NOT EDIT THIS FILE - it is machine generated */  
  2. #include "com_octopus_test03_DefindClassTest.h"  
  3. #include <stdlib.h>  
  4. #include <string.h>  
  5. #include <stdio.h>  
  6. #include <sys/types.h>  
  7. #include <sys/stat.h>  
  8. #include <fcntl.h>  
  9.   
  10. /* 
  11.  * Class:     com_octopus_test03_DefindClassTest 
  12.  * Method:    nativeSetup 
  13.  * Signature: (Ljava/lang/Object;)V 
  14.  */  
  15.   
  16. /* 
  17.    jclass (JNICALL *DefineClass) (JNIEnv *env, const char *name, jobject loader, const jbyte *buf,jsize len); 
  18.    */  
  19.   
  20. jclass mClass;  
  21. jobject mObject;  
  22. jmethodID mid;  
  23.   
  24. JNIEXPORT void JNICALL Java_com_octopus_test03_DefindClassTest_nativeSetup  
  25. (JNIEnv *env, jobject this, jobject weak_this){  
  26.   
  27.   
  28.     int fd;  
  29.     off_t len;  
  30.     jint ret;     
  31.     int pos;      
  32.     off_t tmplen;  
  33.     jbyte *buf = NULL;    
  34.         jclass testclass;  
  35.     jint version =0;  
  36.     jobject mOjbect1;  
  37.     jobject obj1;  
  38.     jclass class = (*env)->GetObjectClass(env,this);  
  39.     mClass =  (jclass)(*env)->NewGlobalRef(env,class);  
  40.       
  41.     //我們需要獲取到DefineClassTest該類的類加載器.  
  42.     mObject = (*env)->NewGlobalRef(env,weak_this);   
  43.   
  44.     //使用c讀取我們需要加載的文件.  
  45.     fd = open("/system/Test.class",O_RDONLY);         
  46.     len = lseek(fd, 0, SEEK_END);  
  47.     buf = calloc(len,1);  
  48.     if(buf == NULL){  
  49.         printf("calloc error \n");    
  50.         return;  
  51.     }  
  52.     lseek(fd, 0,SEEK_SET);  
  53.     pos = 0;  
  54.     tmplen = len;  
  55.     while(tmplen > 0){  
  56.         ret += read(fd,buf+ret,tmplen-ret);  
  57.         pos +=ret;  
  58.         tmplen -=ret;  
  59.     }  
  60.     close(fd);  
  61.      
  62.     //使用DefineClass函數加載這個類  
  63.     testclass = (*env)->DefineClass(env,"Test",mObject,buf,len);  
  64.           
  65.         if(testclass == NULL)  
  66.     {  
  67.         return;  
  68.     }  
  69.         free(buf);  
  70.          
  71.         obj1 = (*env)->AllocObject(env,testclass);  
  72.     //生成一個對象,並調用該對象的方法.  
  73.     mid = (*env)->GetStaticMethodID(env, mClass,"getVersion","(Ljava/lang/Object;Ljava/lang/Object;II)V");  
  74.     version = (*env)->GetVersion(env);  
  75.     (*env)->CallStaticVoidMethod(env,mClass,mid,this,obj1,1,version);  
  76.   
  77.     return ;  
  78.   
  79. }  



二: FindClass

函數原型:jclass (JNICALL *FindClass) (JNIEnv *env, const char *name);

 描 述: 該函數用於加載本地定義的類。它將搜索由CLASSPATH 環境變量為具有指定名稱的類所指定的目錄和 zip 文件。
          該CLASSPATH一般為:
           #set java environment
           JAVA_HOME=/home/xxx/java/jdk1.6.0_12
           export JRE_HOME=/home/xxx/java/jdk1.6.0_12/jre
           export CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
           export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
           findClass函數的java背景知識在我的博客由介紹:

 參 數: env    java本地接口指針.
        name   需要加載類的簡短名稱.比如下載需要加載一個com/zuoshaohua/Test.java這個類,該參數就是 "com/zuoshaohua/Test"

  返回值:
       返回一個jclass類型的結構體.他對應的是Java中的類相關信息.它是類的字節碼對象. 

 例 程:

    --2.1 流程:

    1.MainActivity的onCreate()方法中初始化一個ManPerson.

    2.在ManPerson的構造函數最后我們會調用nativeSetup把ManPerson對象傳遞到C中.

    3.我們會再C中得到ManPerson的屬性Id信息,並保存起來.並使用findClass()方法獲取Person類字節碼對象,並生成Person對象的全集引用.

    4.當我們點擊應用層的btn時,C會獲取ManPerson的信息.使用bean的setXxx()給Person對象賦值.並返回給對象到java層.

      

   --2.2類圖:

     

  --2.3 Activity代碼
   
[cpp]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:paddingBottom="@dimen/activity_vertical_margin"  
  6.     android:paddingLeft="@dimen/activity_horizontal_margin"  
  7.     android:paddingRight="@dimen/activity_horizontal_margin"  
  8.     android:paddingTop="@dimen/activity_vertical_margin"  
  9.     tools:context=".MainActivity" >  
  10.     <TextView  
  11.         android:id="@+id/personView"  
  12.         android:layout_width="260dp"  
  13.         android:layout_height="100dp"  
  14.         android:layout_alignParentTop="true"  
  15.         android:layout_marginTop="28dp" />  
  16.   
  17.     <Button  
  18.         android:id="@+id/exit"  
  19.         android:layout_width="100dp"  
  20.         android:layout_height="100dp"  
  21.         android:layout_alignBaseline="@+id/run"  
  22.         android:layout_alignBottom="@+id/run"  
  23.         android:layout_marginLeft="30dp"  
  24.         android:layout_toRightOf="@+id/run"  
  25.         android:text="EXIT" />  
  26.   
  27.     <Button  
  28.         android:id="@+id/run"  
  29.         android:layout_width="100dp"  
  30.         android:layout_height="100dp"  
  31.         android:layout_alignLeft="@+id/personView"  
  32.         android:layout_below="@+id/personView"  
  33.         android:layout_marginLeft="31dp"  
  34.         android:layout_marginTop="22dp"  
  35.         android:text="RUN" />  
  36.   
  37. </RelativeLayout>  
 
[java]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. package com.zuoshaohua;  
  2.   
  3. import com.zuoshaohua.ndk.ManPerson;  
  4. import com.zuoshaohua.ndk.NativeExec;  
  5. import com.zuoshaohua.ndk.Person;  
  6.   
  7. import android.os.Bundle;  
  8. import android.app.Activity;  
  9. import android.view.Menu;  
  10. import android.view.View;  
  11. import android.view.View.OnClickListener;  
  12. import android.widget.Button;  
  13. import android.widget.TextView;  
  14.   
  15. public class MainActivity extends Activity implements OnClickListener{  
  16.     private Button runbtn;  
  17.     private Button exitbtn;  
  18.     private ManPerson manPerson;  
  19.     private TextView  personView;  
  20.       
  21.     @Override  
  22.     protected void onCreate(Bundle savedInstanceState) {  
  23.         super.onCreate(savedInstanceState);  
  24.         setContentView(R.layout.activity_main);  
  25.        exitbtn = (Button) this.findViewById(R.id.exit);  
  26.        runbtn = (Button) this.findViewById(R.id.run);  
  27.        personView = (TextView) this.findViewById(R.id.personView);  
  28.        manPerson = new ManPerson("zuoshaohua",33,"男");  
  29.        runbtn.setOnClickListener(MainActivity.this);  
  30.        exitbtn.setOnClickListener(this);  
  31.     }   
  32.       
  33.     @Override  
  34.     public void onClick(View arg0) {  
  35.         int id = arg0.getId();  
  36.         switch (id) {  
  37.         case R.id.run:  
  38.             Person p = (Person)NativeExec.nativeExec();   //獲取c代碼生成對象.  
  39.             personView.setText("name ="+ p.getName()+ "age="+p.getAge()+"gender="+p.getGender()); //輸出這個對象的值.  
  40.             break;  
  41.         case R.id.exit:  
  42.             this.finish();  
  43.             break;  
  44.         default:  
  45.             this.finish();  
  46.             break;  
  47.         }  
  48.     }  
  49. }  


 --2.4 jni代碼

 

[cpp]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. package com.zuoshaohua.ndk;  
  2.   
  3. public class ManPerson {  
  4.       
  5.     private String name;  
  6.     private int age;   
  7.     private String gender;  
  8.   
  9.     static  
  10.     {  
  11.         System.loadLibrary("HelloNdk");         //加載動態庫文件.  
  12.     }  
  13.   
  14.     public ManPerson(String name, int age, String gender){  
  15.         this.name = name;  
  16.         this.age = age;  
  17.         this.gender =gender;  
  18.         nativeSetup();  
  19.     }  
  20.       
  21.     private native void nativeSetup();  
  22. }  

 

[java]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. package com.zuoshaohua.ndk;  
  2.   
  3. public class NativeExec {  
  4.     public static native Object nativeExec();  
  5. }  

 

[java]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. package com.zuoshaohua.ndk;  
  2.   
  3. public class Person {  
  4.     private String name;  
  5.     private int age;   
  6.     private String gender;  
  7.       
  8.     public String getName() {  
  9.         return name;  
  10.     }  
  11.     public void setName(String name) {  
  12.         this.name = name;  
  13.     }  
  14.       
  15.     public int getAge() {  
  16.         return age;  
  17.     }  
  18.     public void setAge(int age) {  
  19.         this.age = age;  
  20.     }  
  21.       
  22.     public String getGender() {  
  23.         return gender;  
  24.     }  
  25.     public void setGender(String gender) {  
  26.         this.gender = gender;  
  27.     }  
  28.       
  29. }  

 

--2.5 c層代碼
[cpp]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. #include "com_zuoshaohua_ndk_ManPerson.h"  
  2. #include "com_zuoshaohua_ndk_NativeExec.h"  
  3. /* 
  4.  * Class:     com_zuoshaohua_ndk_ManPerson 
  5.  * Method:    nativeSetup 
  6.  * Signature: ()V 
  7.  */  
  8.   
  9. jobject m_obj, p_obj;   
  10. jfieldID name_id,age_id,gender_id;  
  11.   
  12. jmethodID pname_mid,page_mid,pgender_mid;  
  13.   
  14. JNIEXPORT void JNICALL Java_com_zuoshaohua_ndk_ManPerson_nativeSetup  
  15.   (JNIEnv *env, jobject this)  
  16. {         
  17.   
  18. #if 1  
  19.   
  20.     jclass clz = (*env)->GetObjectClass(env,this);   //通過ManPerson的對象獲取ManPerson字節碼對象.  
  21.   
  22.     m_obj = (*env)->NewGlobalRef(env,this);       //將這個對象設置為全局引用.  
  23.    
  24.     name_id = (*env)->GetFieldID(env,clz,"name","Ljava/lang/Object;"); //獲取ManPerson對象的屬性.     
  25.   
  26.     age_id = (*env)->GetFieldID(env,clz,"age","I");  
  27.   
  28.     gender_id = (*env)->GetFieldID(env,clz,"gender","Ljava/lang/Object;");         
  29.       
  30.     jclass personclz = (*env)->FindClass(env,"com/zuoshaohua/ndk/Person"); //通過FindClass方法獲取Person類的字節碼對象.  
  31.       
  32.     jmethodID  constr =(*env)->GetMethodID(env,personclz,"<init>", "()V"); //獲取這個對象無參的構造函數.  
  33.       
  34.     jobject ref = (*env)->NewObject(env,personclz,constr);           //生成Person對象.  
  35.   
  36.     p_obj = (*env)->NewGlobalRef(env, ref);                    //將Person對象設置為全局引用.  
  37.       
  38.     pname_mid = (*env)->GetMethodID(env,personclz,"setName","(Ljava/lang/Object;)V"); //獲取Person的Setxxx()方法的ID.  
  39.       
  40.     page_mid = (*env)->GetMethodID(env,personclz,"setAge", "(I)V");   
  41.   
  42.    pgender_mid = (*env)->GetMethodID(env,personclz,"setGender","(Ljava/lang/Object;)V");   
  43. #endif  
  44. }  
  45.   
  46. /* 
  47.  * Class:     com_zuoshaohua_ndk_NativeExec 
  48.  * Method:    nativeExec 
  49.  * Signature: ()Ljava/lang/Object; 
  50.  */  
  51. JNIEXPORT jobject JNICALL Java_com_zuoshaohua_ndk_NativeExec_nativeExec  
  52.   (JNIEnv *env, jclass this)  
  53. {  
  54. #if 1  
  55.     jint age = 0;   
  56.     jstring name,gender;  
  57.   
  58.     name = (*env)->GetObjectField(env,m_obj,name_id);         //獲取ManPerson屬性的值.  
  59.     gender = (*env)->GetObjectField(env,m_obj,gender_id);  
  60.     age = (*env)->GetIntField(env,m_obj,age_id);  
  61.   
  62.     (*env)->CallVoidMethod(env, p_obj,pname_mid,name);    //調用Person的Setxxx()方法給Person對象賦值.  
  63.     (*env)->CallVoidMethod(env, p_obj,page_mid,age);   
  64.     (*env)->CallVoidMethod(env, p_obj,pgender_mid,gender);     
  65.     //(*env)->SetIntField(env,p_obj,age_id,10);         //返回Person對象.  
  66.     return p_obj;   
  67. #endif    
  68. }  

 

轉載請注明出處: http://blog.csdn.net/shaohuazuo/article/details/42932813

3.3 java反射相關模塊

jmethodID (JNICALL *FromReflectedMethod)(JNIEnv *env, jobject method);

jfieldID (JNICALL *FromReflectedField) (JNIEnv *env, jobject field);

jobject (JNICALL *ToReflectedMethod)(JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic);

jobject (JNICALL *ToReflectedField) (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic);

 函數背景知識介紹: 請看博客(Java反射機制)  

java.lang.reflect:

提供類和接口,以獲得關於類和對象的反射信息。在安全限制內,

反射允許編程訪問關於加載類的字段、方法和構造方法的信息,

並允許使用反射字段、方法和構造方法對其底層對等項進行操作。

更多相關知識可以參考http://www.javaweb.cc/help/JavaAPI1.6/

也可以進入博客:?????????????

 一:FromReflectedMethod

函數原型: jmethodID (JNICALL *FromReflectedMethod)(JNIEnv *env, jobject method);

 描 述: 通過java.lang.reflect中Method類的對象獲取一個函數的MethodID. 就可以調用Java中某個方法.

 參 數: env    java native interface porint,(java本地接口指針)

    method    這個是jva.lang.reflect.Method對象.

         要獲取Method對象第一步.需要獲取Class對象.再通過Class對象獲取Method.

          1.獲取Class對象的三種方法是:

        1.1) 類名.class,例如 Class pclass =  Person.class

        1.2) 對象.getClass(),例如,Class  pclass = new Person().getClass()

        1.3) Class.forName(“類名”),例如,Class pclass = Class.forName(“com.zuoshaohua.Person”);

                    2.獲取Method對象,詳細方法介紹可以參考http://www.javaweb.cc/help/JavaAPI1.6/手冊

                        2.1)Class.getMethods(),

             2.2)Class.getMethod(String, Class[]),

             2.3)Class.getDeclaredMethods(),

          2.4)Class.getDeclaredMethod(String, Class[])

                            1.5) ToReflectedMethod()通過C中的JNI標准獲取Methdod對象.

  返回值:返回一個方法的MethodID指針.

 二:FromReflectedField

函數原型: jfieldID (JNICALL *FromReflectedField) (JNIEnv *env, jobject field);

 描 述:通過java.lang.reflect中Field類的對象獲取字段對象.可以獲取這個字段的jfieldID了.

 參 數:  env   java native interface porint,(java本地接口指針)

       field   Field對象,這個對象主要用來描述java中的字段信息.通過這個類對象.我們可以獲得

          這個字段的名稱,類型等等信息.

      1.獲取這個對象由如下5種方法:

            1.1)Class.getDeclaredField(String name);

                 返回一個 Field 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明字段。

            1.2)Class.getDeclaredFields();

                 返回 Field 對象的一個數組,這些對象反映此 Class 對象所表示的類或接口所聲明的所有字段。

            1.3)Class.getField(String name);

                返回一個 Field 對象,它反映此 Class 對象所表示的類或接口的指定公共成員字段。

            1.4)Class.getField();

                返回一個包含某些 Field 對象的數組,這些對象反映此 Class 對象所表示的類或接口的所有可訪問公共字段。 

            1.6)ToReflectedFile()

                 通過C中JNI標准中提供的上面的函數,也可以獲取Field對象.

  返回值:返回一個字段的jfieldID指針.

 三:ToReflectedMethod

函數原型: jobject (JNICALL *ToReflectedMethod)(JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic);

 描 述: 這個方法是通過方法的methodId返回一個java.lang.reflect.Method對象,是FromReflectedMethod的反操作.

  參 數: env      java native interface porint,(java本地接口指針)

         cls       該方法的類對象.可以通過FindClass()獲取.如果知道對象的話可以使用GetObjectClass()來獲取這個jclass對象.

    methodID       這個對象是jmethodID指針.可以通過GetMethodID方法獲取.

    isStatic     該方法是不是靜態的,JNI標准中提供了兩個宏表示.JNI_FALSE,和JNI_TRUE.

  返回值:返回一個Method對象.也就是說再FromReflectedMethod 中多了一種方法可以獲取Method對象的方法.

 

 四:ToReflectedField

函數原型: jobject (JNICALL *ToReflectedField) (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic);

 描 述: 通過filedID可以返回一個java.lang.reflect.Field對象.

 參 數: env java native interface porint,(java本地接口指針)

         cls  該方法的類對象.可以通過FindClass()獲取.如果知道對象的話可以使用GetObjectClass()來獲取這個jclass對象.

   methodID  這個對象是jField指針.可以通過GetFieldID方法獲取.

   isStatic  該方法是不是靜態的,JNI標准中提供了兩個宏表示.JNI_FALSE,和JNI_TRUE.    

  返回值: 返回一個Field對象.

 

 五:例程

  1.1 流程     

   1. 定義一個Person類.這個Person類三個屬性.name, age, gender.還有getxxx()和setxxx()方法.

     2. 定義一個Android的界面.它的MainActivity類關聯了一個Person對象.也就是,Person類是Activity的一個屬性.

     3. 在MainActivity中,靜態初始化這個Person對象.我們使用該靜態對象.p.getClass()獲取類Class對象clz. 

     4. 我們需要獲取這個Class中的Method對象和Field對象.clz.getMethod(); clz.getField對象.

     通過 ReflectMethodDeom本地方法和ReflectFieldDemo本地方法傳入到C層.

   5. c通過這兩個對象獲取到對象的jfieldID對象和jmethodID.並進行相應的操作.

 

  1.2    類圖

         

  1.3   代碼  

   1. MainActivity代碼

    

[java]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. package com.zuoshaohua.reflect;  
  2.   
  3. import java.lang.reflect.Field;  
  4. import java.lang.reflect.InvocationTargetException;  
  5. import java.lang.reflect.Method;  
  6.   
  7. import android.os.Bundle;  
  8. import android.app.Activity;  
  9. import android.view.Menu;  
  10. import android.view.View;  
  11. import android.view.View.OnClickListener;  
  12. import android.widget.Button;  
  13. import android.widget.TextView;  
  14.   
  15. public class MainActivity extends Activity implements OnClickListener {  
  16.     private static Person  p = new Person("zuoshaohua",33,"男");  
  17.     private Button runBtn;  
  18.     private Button exitBtn;  
  19.     TextView textView;  
  20.     static {  
  21.         System.loadLibrary("reflect");  
  22.     }  
  23.       
  24.     @Override  
  25.     protected void onCreate(Bundle savedInstanceState) {  
  26.          
  27.         super.onCreate(savedInstanceState);  
  28.         setContentView(R.layout.activity_main);  
  29.           
  30.         runBtn  = (Button)this.findViewById(R.id.run);  
  31.         exitBtn = (Button)this.findViewById(R.id.exit);  
  32.         textView = (TextView)this.findViewById(R.id.personView);  
  33.         
  34.         this.runBtn.setOnClickListener(this);  
  35.         this.exitBtn.setOnClickListener(this);  
  36.           
  37.     }  
  38.       
  39.     private void refelectTest(){  
  40.         Class<? extends Person> c =  p.getClass();  
  41.         try {  
  42.               
  43.             StringBuffer sb = new StringBuffer();  
  44.               
  45.             Method method = c.getMethod("setAge", int.class);  
  46.               
  47.             //Field field = c.getField("age");  
  48.               
  49.             Field field = c.getDeclaredField("age");  
  50.             sb.append("oldName ="+p.getName()+"oldAge="+p.getAge()+ "oldGender="+p.getGender()+"\n");  
  51.               
  52.               
  53.             Field field1 = ReflectFieldDemo(p,field);   //調用本地方法.將描述age字段的Field對象傳進去.  
  54.               
  55.             //field1.set(p, "shaohuazuo");  
  56.               
  57.             Method m1 = ReflectMethodDemo(p,method);    //調用本地方法.將描述setAge()方法的Method對象傳入到C層代碼.  
  58.              
  59.             sb.append("oldName1 ="+p.getName()+"oldAge1="+p.getAge()+ "oldGender1="+p.getGender()+"\n");  
  60.              
  61.             Object args[] = new Object[1];  
  62.               
  63.             args[0] = new  String("shaohuazuo");  
  64.               
  65.             m1.invoke(p, args);                         //調用返回的方法.  
  66.               
  67.             field1.setAccessible(true);  
  68.              
  69.             String name =(String)field1.get(p);  
  70.               
  71.             sb.append("newName ="+name+"newAge="+p.getAge()+"newGender="+p.getGender());  
  72.               
  73.             textView.setText(sb.toString());      
  74.               
  75.         } catch (NoSuchMethodException e) {  
  76.             e.printStackTrace();  
  77.         } catch (NoSuchFieldException e) {  
  78.             // TODO Auto-generated catch block  
  79.             e.printStackTrace();  
  80.         } catch (IllegalAccessException e) {  
  81.             // TODO Auto-generated catch block  
  82.             e.printStackTrace();  
  83.         } catch (IllegalArgumentException e) {  
  84.             // TODO Auto-generated catch block  
  85.             e.printStackTrace();  
  86.         } catch (InvocationTargetException e) {  
  87.             // TODO Auto-generated catch block  
  88.             e.printStackTrace();  
  89.         }  
  90.     }  
  91.       
  92.     @Override  
  93.     public boolean onCreateOptionsMenu(Menu menu) {  
  94.         // Inflate the menu; this adds items to the action bar if it is present.  
  95.         getMenuInflater().inflate(R.menu.main, menu);  
  96.         return true;  
  97.     }  
  98.       
  99.     private  static native Field ReflectFieldDemo(Person p,Field f);  
  100.     private  static native Method ReflectMethodDemo(Person p, Method m);  
  101.   
  102.   
  103.     @Override  
  104.     public void onClick(View arg0) {  
  105.         // TODO Auto-generated method stub  
  106.         switch(arg0.getId())  
  107.         {  
  108.         case R.id.run:  
  109.             refelectTest();  
  110.             break;  
  111.         case R.id.exit:  
  112.             this.finish();  
  113.             break;   
  114.             default:  
  115.                 this.finish();  
  116.                 break;  
  117.         }  
  118.     }   
  119. }  

 

     2. Person.java代碼

 

[java]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. package com.zuoshaohua.reflect;  
  2.   
  3. public class Person {  
  4.       
  5.     private String name;  
  6.     private int age;  
  7.     private String gender;  
  8.   
  9.     public Person(String string, int age, String gender) {  
  10.         this.name = name;  
  11.         this.age = age;   
  12.         this.gender = gender;  
  13.     }  
  14.     public String getName() {  
  15.         return name;  
  16.     }  
  17.     public void setName(String name) {  
  18.         this.name = name;  
  19.     }  
  20.     public int getAge() {  
  21.         return age;  
  22.     }  
  23.     public void setAge(int age) {  
  24.         this.age = age;  
  25.     }  
  26.     public String getGender() {  
  27.         return gender;  
  28.     }  
  29.     public void setGender(String gender) {  
  30.         this.gender = gender;  
  31.     }     
  32.   
  33. }  

 

 

     3. 生成.h頭文件.

        zshh@HP:~/work/android/jni/Reflect/jni$

                javah -o reflect.h -classpath ../bin/classes com.zuoshaohua.reflect.MainActivity
        

     4. reflect.h代碼

      

[cpp]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. /* DO NOT EDIT THIS FILE - it is machine generated */  
  2. #include <jni.h>  
  3. /* Header for class com_zuoshaohua_reflect_MainActivity */  
  4.   
  5. #ifndef _Included_com_zuoshaohua_reflect_MainActivity  
  6. #define _Included_com_zuoshaohua_reflect_MainActivity  
  7. #ifdef __cplusplus  
  8. extern "C" {  
  9. #endif  
  10. /* 
  11.  * Class:     com_zuoshaohua_reflect_MainActivity 
  12.  * Method:    ReflectFieldDemo 
  13.  * Signature: (Lcom/zuoshaohua/reflect/Person;Ljava/lang/reflect/Field;)Ljava/lang/reflect/Field; 
  14.  */  
  15. JNIEXPORT jobject JNICALL Java_com_zuoshaohua_reflect_MainActivity_ReflectFieldDemo  
  16.   (JNIEnv *, jclass, jobject, jobject);  
  17.   
  18. /* 
  19.  * Class:     com_zuoshaohua_reflect_MainActivity 
  20.  * Method:    ReflectMethodDemo 
  21.  * Signature: (Lcom/zuoshaohua/reflect/Person;Ljava/lang/reflect/Method;)Ljava/lang/reflect/Method; 
  22.  */  
  23. JNIEXPORT jobject JNICALL Java_com_zuoshaohua_reflect_MainActivity_ReflectMethodDemo  
  24.   (JNIEnv *, jclass, jobject, jobject);  
  25.   
  26. #ifdef __cplusplus  
  27. }  
  28. #endif  
  29. #endif  

 

     5. reflect.c代碼

 

[cpp]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. #include "reflect.h"  
  2. #include <android/log.h>  
  3. #include <stdio.h>  
  4.   
  5. #if 0  
  6.   
  7. jmethodID (JNICALL *FromReflectedMethod) (JNIEnv *env, jobject method);  
  8. jfieldID (JNICALL *FromReflectedField) (JNIEnv *env, jobject field);  
  9.   
  10. jobject (JNICALL *ToReflectedMethod) (JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic);  
  11.   
  12. jobject (JNICALL *ToReflectedField) (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic);  
  13.   
  14.   
  15. #endif  
  16. jclass clazz;  
  17. /* 
  18.  * Class:     com_zuoshaohua_reflect_MainActivity 
  19.  * Method:    ReflectFieldDemo 
  20.  * Signature: (Lcom/zuoshaohua/reflect/Person;Ljava/lang/reflect/Field;)Ljava/lang/reflect/Field; 
  21.  */  
  22.   
  23.   
  24. JNIEXPORT jobject JNICALL Java_com_zuoshaohua_reflect_MainActivity_ReflectFieldDemo  
  25.   (JNIEnv * env, jclass this, jobject pthis, jobject fthis)  
  26. {  
  27.     jint age =0;      
  28.     jclass clz =(*env)->GetObjectClass(env,pthis);     //通過Person對象獲取他的Class對象信息,從而得到一個jclass對象.  
  29.       
  30.     jfieldID age_id = (*env)->FromReflectedField(env,fthis); //通過Field對象獲取Person屬性的jfieldID指針.  
  31.   
  32.     age = (*env)->GetIntField(env,pthis,age_id);               //通過這個對象和age_id獲取這個屬性的值.  
  33.   
  34.   
  35.     __android_log_print(ANDROID_LOG_INFO, "ReFlectFieldDemo", "age: %d", age);  
  36.               
  37.   
  38.     jfieldID name_id = (*env)->GetFieldID(env,clz,"name","Ljava/lang/String;");  //獲取name字段的jfieldID.  
  39.       
  40.     __android_log_print(ANDROID_LOG_INFO, "ReFlectFieldDemo", "end!!!!!");  
  41.   
  42.     return (*env)->ToReflectedField(env,clz,name_id,JNI_FALSE);    //通過jfieldID生成一個Java的Field對象.並返回.  
  43.       
  44. }  
  45.   
  46. /* 
  47.  * Class:     com_zuoshaohua_reflect_MainActivity 
  48.  * Method:    ReflectMethodDemo 
  49.  * Signature: (Lcom/zuoshaohua/reflect/Person;Ljava/lang/reflect/Method;)Ljava/lang/reflect/Method; 
  50.  */  
  51. JNIEXPORT jobject JNICALL Java_com_zuoshaohua_reflect_MainActivity_ReflectMethodDemo  
  52.   (JNIEnv *env , jclass this, jobject pthis, jobject mthis)  
  53. {  
  54.     //我們使用mthis.來獲取jmethodID指針.並通過該指針調用到set方法.來改變Person屬性的值.   
  55.     jclass pclazz = (*env)->GetObjectClass(env,pthis);   
  56.   
  57.     jmethodID setAgeId = (*env)->FromReflectedMethod(env,mthis);   
  58.   
  59.     (*env) ->CallVoidMethod(env,pthis,setAgeId,100);    
  60.       
  61.     __android_log_print(ANDROID_LOG_INFO,"ReflectMethodDemo","is callVoidMethod Done!!!!\n");   
  62.   
  63.     jmethodID setName_id = (*env)->GetMethodID(env,pclazz,"setName","(Ljava/lang/String;)V");   
  64.   
  65.   
  66.     return (*env)->ToReflectedMethod(env, pclazz,setName_id, JNI_FALSE);  
  67. }  

 

 

     6. Android.mk代碼

 

[cpp]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. SRC_PATH_ROOT:=$(LOCAL_PATH)/../../src    
  2. LOCAL_PATH := $(call my-dir)  
  3.   
  4. include $(CLEAR_VARS)  
  5.   
  6. LOCAL_MODULE    := reflect  
  7. LOCAL_SRC_FILES := reflect.c   
  8. LOCAL_LDLIBS := -llog  
  9. #LOCAL_SHARED_LIBRARIES :=libc  
  10. include $(BUILD_SHARED_LIBRARY)                                                                                                                                                        



 

  1.4  測試結果

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM