- 這個方法的觀念很簡單,就是:既然java native function是屬於某一個class,理論上它就可以存取這個class裡所有的member fields。因此,這個class中所有的函式,無論在java還是C++,都可以對同一組資料做存取而無需透過參數傳遞。
- The Java programming language supports two kinds of fields.
- (Object) Each instance of a class has its own copy of the instance fields of the class.
- (Class) All instances of a class share the static fields of the class. The JNI provides functions that native code can use to get and set instance fields in objects and static fields in classes.
- Access Object Fileds
- InstanceFieldAccess.java
- Generate C header file: InstanceFieldAccess.h
- C implementation of InstanceFieldAccess.c
- First, it calls GetFieldID to obtain the field ID from the class reference, field name, and field descriptor:
- Once you have obtained the field ID, you can pass the object reference and the field ID to the appropriate instance field access function (ex. GetObjectField):
- Generate shared library file - libInstanceFieldAccess.so
- RUN InstanceFieldAccess output:
- Access Static Fields
- StaticFielcdAccess.java
- Generate c header file: StaticFielcdAccess.h
- C implementation of StaticFieldAccess.c
- Generate shared library file - libStaticFieldAccess.so
- RUN StaticFieldAccess output:
- Usage: call GetStaticFieldID for static fields, as opposed to GetFieldID for instance fields. GetStaticFieldID and GetFieldID have the same return type jfieldID.
- Once you have obtained the static field ID, you pass the class reference, as opposed to an object reference, to the appropriate static field access function (such as GetStaticIntField for static int field).
- JNI Field Descriptors
- The specially encoded C string "Ljava/lang/String;" to represent a field type (such as java.lang.String) in the Java programming language. These C strings are called JNI field descriptors.
- Descriptors Query Tool: "javap" tool (shipped with JDK or Java 2 SDK releases) to generate the field descriptors from class files.
- -s option: print internal type signatures
- -p option: exposing private members
(Example) InstanceFieldAccess.java: The main method creates an object, sets the instance field, and then calls the native method (InstanceFieldAccess.accessField) to print out the existing value of the instance field and then set the field to a new value.
class InstanceFieldAccess { private String s; private native void accessField(); public static void main(String args[]) { InstanceFieldAccess c = new InstanceFieldAccess(); c.s = "abc"; c.accessField(); System.out.println("In Java:"); System.out.println(" c.s = \"" + c.s + "\""); } static { System.loadLibrary("InstanceFieldAccess"); } }
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class InstanceFieldAccess */ #ifndef _Included_InstanceFieldAccess #define _Included_InstanceFieldAccess #ifdef __cplusplus extern "C" { #endif /* * Class: InstanceFieldAccess * Method: accessField * Signature: ()V */ JNIEXPORT void JNICALL Java_InstanceFieldAccess_accessField (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
#include <stdio.h> #include <jni.h> JNIEXPORT void JNICALL Java_InstanceFieldAccess_accessField(JNIEnv *env, jobject obj) { jfieldID fid; /* store the field ID */ jstring jstr; const char *str; /* Get a reference to obj's class */ jclass cls = (*env)->GetObjectClass(env, obj); printf("In C:\n"); /* Look for the instance field s in cls */ fid = (*env)->GetFieldID(env, cls, "s", "Ljava/lang/String;"); if (fid == NULL) { return; /* failed to find the field */ } /* Read the instance field s */ jstr = (*env)->GetObjectField(env, obj, fid); str = (*env)->GetStringUTFChars(env, jstr, NULL); if (str == NULL) { return; /* out of memory */ } printf(" c.s = \"%s\"\n", str); (*env)->ReleaseStringUTFChars(env, jstr, str); /* Create a new string and overwrite the instance field */ jstr = (*env)->NewStringUTF(env, "123"); if (jstr == NULL) { return; /* out of memory */ } (*env)->SetObjectField(env, obj, fid, jstr); }
- To access an instance field, the native method follows a two-step process.
fid = (*env)->GetFieldID(env, cls, "s", "Ljava/lang/String;");
jstr = (*env)->GetObjectField(env, obj, fid);
P.S. Strings & Arrays (special objects) : use GetObjectField to access the instance fields.
Primitive types : use GetIntField and SetFloatField for accessing instance fields.
gcc -shared -I/usr/local/jdk1.6.20_21/include -I/usr/local/jdk1.6.20_21/include/linux InstanceFieldAccess.c -o libInstanceFieldAccess.so
In C: c.s = "abc"
In Java: c.s = "123"
- Accessing static fields is similar to accessing instance fields.
(Example) StaticFielcdAccess.java: The main method creates an object, initializes the static field, and then calls the native method (StaticFieldAccess.accessField) to print out the existing value of the static field and then set the field to a new value.
class StaticFieldAccess { private static int si; private native void accessField(); public static void main(String args[]) { StaticFieldAccess c = new StaticFieldAccess(); StaticFieldAccess.si = 100; c.accessField(); System.out.println("In Java:"); System.out.println(" StaticFieldAccess.si = " + si); } static { System.loadLibrary("StaticFieldAccess"); } }
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class StaticFieldAccess */ #ifndef _Included_StaticFieldAccess #define _Included_StaticFieldAccess #ifdef __cplusplus extern "C" { #endif /* * Class: StaticFieldAccess * Method: accessField * Signature: ()V */ JNIEXPORT void JNICALL Java_StaticFieldAccess_accessField (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
#include <stdio.h> #include <jni.h> JNIEXPORT void JNICALL Java_StaticFieldAccess_accessField(JNIEnv *env, jobject obj) { jfieldID fid; /* store the field ID */ jint si; /* Get a reference to obj's class */ jclass cls = (*env)->GetObjectClass(env, obj); printf("In C:\n"); /* Look for the static field si in cls */ fid = (*env)->GetStaticFieldID(env, cls, "si", "I"); if (fid == NULL) { return; /* field not found */ } /* Access the static field si */ si = (*env)->GetStaticIntField(env, cls, fid); printf(" StaticFieldAccess.si = %d\n", si); (*env)->SetStaticIntField(env, cls, fid, 200); }
gcc -shared -I/usr/local/jdk1.6.20_21/include -I/usr/local/jdk1.6.20_21/include/linux StaticFieldAccess.c -o libStaticFieldAccess.so
In C: StaticFieldAccess.si = 100
In Java: StaticFieldAccess.si = 200
There are two differences between how access a static field and how access an instance field:
javap -s -p CLASS_NAME
1 意見:
想不到在找JNI的資訊時會遇到老朋友,哈哈
張貼留言