zoukankan      html  css  js  c++  java
  • 【转】 jni.h头文件详解(二)

    原文网址:http://blog.csdn.net/shaohuazuo/article/details/42932813

    作者:左少华
    博客: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 ");  
    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  ");    
    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()+" ");  
    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()+" ");  
    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!!!! ");   
    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  测试结果



    作者:左少华
    博客:http://blog.csdn.net/shaohuazuo/article/details/42932813
    转载请注明出处:http://blog.csdn.net/shaohuazuo
  • 相关阅读:
    六大关系整理
    pthread_create多线程执行顺序诡异现象
    WinForm中 事件 委托 多线程的应用
    伪ajax上传文件
    Webx小应用的实现整理与分析
    IL反编译的实用工具
    MVC4+WebApi+Redis Session共享练习(上)
    虚拟化平台cloudstack新版本的调试
    【c++】指针参数是如何传递内存的
    NPinyin 中文转换拼音代码
  • 原文地址:https://www.cnblogs.com/wi100sh/p/5178709.html
Copyright © 2011-2022 走看看