JNI全攻略之——操作Java对象的属性

来源:互联网 发布:计算机数据安全技术 编辑:程序博客网 时间:2024/06/03 19:48

本篇讲述如何在本地方法中操作java对象的属性。该属性可以是实例变量也可以是类变量。下面是两个例子。

一、              操作属性

       类的属性包含两种:实例变量和类变量。下面就分别讲解吧!(很多读者都说以前的关于JNI文章讲解太少了,不太能看懂,下面的文章我将比较详细地讲解。)

1.1实例变量

       下面是一个包含一个本地方法的类,该类有基本数据类型型的属性、String类型的属性以及自定义类型的属性,几乎可以包含我们所有类型的实例属性。

       // InstanceFieldAccess.java

public class InstanceFieldAccess {

       //下面是3种类型的实例变量

       private String str;

       private int attr ;

       private Employee emp ;

      

       private native void accessField();                //访问以上属性的本地方法

      

       public static void main(String args[]) {          //main方法,不用说了吧!

              InstanceFieldAccess c = new InstanceFieldAccess();                     //实例化该对象

              c.str = "abc";                   //不是private的,怎么可以使用啊?想想吧!为什么

              c.attr = 5;                         //private是内外不能访问,这可是在类的内部哦!

              c.emp=new Employee("master24",28);                       //创建一个引用类型的属性

              c.accessField();                                                               //调用该本地方法,实现在后面

              System.out.println("In Java:");                                      //java中输出

              System.out.println(" c.str = "" + c.str + " "");                            //看看在JNI中操作的属性,

                                                                                                  //java中是否有“后遗症”

       }

      

       static {                                                               //在类构造前,加载动态链接库

              System.loadLibrary("InstanceFieldAccess");

       }

}

 

 

class Employee{                            //一个辅助类,我们会用它做一个复杂的调用

       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文件,不会请参考第一篇

#include <stdio.h>

#include <stdarg.h>

#include <jni.h>

 

JNIEXPORT void JNICALL Java_InstanceFieldAccess_accessField(JNIEnv *env, jobject obj){

       //以下三段,不同色的分别演示操作String类型的属性、int类型的属性、对象属性

       jfieldID fid;                 //存放属性(field)的标识符(ID),看到了吧,一般称fid

       jstring jstr;                //JNI中的String

       const char *str;        //

 

       jint int1 ;                            //JNI中的int

 

       jobject empobj ;        //属性Employee的实例

       jclass empcls;                //属性Employee的类

 

       jclass cls = (*env)->GetObjectClass(env, obj);              //得到该对象的class,第一步哦!

       printf("In C: n");                                                   //本地输出方法

      

       fid = (*env)->GetFieldID(env, cls, "str","Ljava/lang/String;");    //得到属性的标识符

                                                                                    //第一个参数为env      

                                                                                    //第二个参数为上面第一步的class

                                                                                    //第三个是InstanceFieldAccess.java

                                                                                    //                                   中属性的名称

                                                                                    //第四个是方法的返回值,将Signature

                                                                                    //                                      第二步哦!

                                                                                    //实例变量和类的变量使用不同方法

       if (fid == NULL) {

              return;                                                                //没有得到此fid就返回

       }

      

       jstr = (*env)->GetObjectField(env, obj, fid);                //得到实例的属性,第三步哦! 

                                                                                    //一般格式为Get <Type>Field

                                                                                    //实例变量和类变量不同

       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");                     //创建一个String

       if (jstr == NULL) {              return;        }

       (*env)->SetObjectField(env, obj, fid, jstr);               //将此String赋值给此成员变量

 

       //第二部分

       fid = (*env)->GetFieldID(env, cls, "attr","I");               //得到类型为int属性attrID

       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属性empID

       if (fid == NULL) {              return;       }

      

       empobj = (*env)->GetObjectField(env, obj, fid);         //同上,Get<Type>Field

       if (empobj== NULL) {          return;        }                    //此时我们得到一个Employee的实例

 

       empcls = (*env)->GetObjectClass(env, empobj);        //得到EmployeeClass

       printf("In C: n Use Employee Instance !");                     //在本地代码中输出

       fid = (*env)->GetFieldID(env, empcls , "name","Ljava/lang/String;");

                                                                                    //继续得到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);  //释放,不过肯定少释放一次!找找在哪里

 

}

 

       操作类的实例属性分为三步:

1.         得到类的类。使用函数:

              jclass GetObjectClass(JNIEnv *env, jobject obj);

2.         得到你要要的实例属性的标识符。使用函数:

              jfieldID GetFieldID(JNIEnv *env, jclass clazz,const char *name, const char *sig);

3.         得到该属性对应的值。使用函数

              <NativeType> Get<Type>Field(JNIEnv *env,jobject obj, jfieldID fieldID);

       一定要看好了参数哦!

 


 

1静态成员变量

       这个例子相对比较简单点!一个包含本地方法的类!主要包含两个静态的属性,一个为String类型,另外一个为自定义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();              //创建类的实例

              StaticFieldAccess.str = "I'm Static!";                               //给类的静态属性赋值

              sfa.accessStaticField();                                                     //调用本地方法

              System.out.println("In Java:");                                      //java中输出

              System.out.println(" StaticFieldAccess.str = " + str);

       }

       static {

              System.loadLibrary("StaticFieldAccess");

       }

}

 

class Manager{                                                                             //简单的包含静态属性的类

       static String company="Microsoft!";                                  

}

 

       JNI的实现。主要演示:1.访问类的String类型的静态属性str2.访问类的Manager类型的属性mgr,接着访问该实例的String类型的静态属性company。看起来较复杂,好好理解就很很简单了!

#include <jni.h>

JNIEXPORT void JNICALL Java_StaticFieldAccess_accessStaticField (JNIEnv *env , jobject obj){

       //一系列访问类的静态属性用到的中间变量

       jclass cls ;                                                  //该类的类

       jfieldID fid  ;                                               //方法的标识符

       jobject str ;                                                   //String类型属性的对象

       const char *jstr ;                                                 //JNI中的String

       jstring  newstr ;                                             //JNI中新创建的String

 

       //相应地以下是访问类的Manager类型静态属性(此时得到Managermgr

       //的静态的String类型的属性的中间变量(此时得到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

}

 

以下是执行结果!

In Java:

 StaticFieldAccess.str = XXXXXXXXXXXXX

In C:

 StaticFieldAccess.str = I'm Static!

In C:

 Use Manager Class ! StaticFieldAccess.mgr.Company = Microsoft!

 

 

       操作类的实例属性分为三步:

1.         得到类的类。使用函数:

              jclass GetObjectClass(JNIEnv *env, jobject obj);

2.         得到你要要的实例属性的标识符。使用函数:

              jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz,const char *name, const char *sig);

3.         得到该属性对应的值。使用函数

              <NativeType> GetStatic<Type>Field(JNIEnv *env,jclass cls , jfieldID fieldID);

       一定要看好了参数哦!

 

 

       以前都使用那个黑漆漆的贴图,现在使用文字结果了!怎么搞啊!

java StaticFieldAccess >1.txt  这样你运行StaticFieldAccess的结果就放到与你的类同目录的文本文件1.txt中了!有意思吧!

 

1.3操作属性的差异:

       主要在第23步。第二步GetFieldID GetStaticFieldID看到了吧!参数的个数和意义相同!第三步Get<Type>FieldGetStatic<Type>Field名称不同,且第二个参数,实例属性的为jobject,类属性的为jclass。和java中极其类似吧!

原创粉丝点击