在上一章中我们学习到了如何在本地代码中访问任意Java类中的静态方法和实例方法,本章我们也通过一个示例来学习Java中的实例变量和静态变量,在本地代码中如何来访问和修改。静态变量也称为类变量(属性),在所有实例对象中共享同一份数据,可以直接通过【类名.变量名】来访问。实例变量也称为成员变量(属性),每个实例都拥有一份实例变量数据的拷贝,它们之间修改后的数据互不影响。下面看一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
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实例作为形参,用于访问该对象中的实例变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
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。这两个变量会被本地代码访问和修改。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/* 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方法生成的本地代码函数原型头文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
// 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 |