This series of articles are as follows:
Android JNI learning (1) - NDK and JNI basic
Android JNI learning (2) - "hello world" of actual JNI
Android JNI learning (3) - Java and Native call each other
Android JNI learning (4) - JNI Chinese API for common methods
This article is mainly based on the translation of JNI's common interface documents to help us better understand the commonly used APIs in JNI. details as follows:
1. Interface Function Table (interface function table)
Each function can be accessed through the JNIEnv parameter. The JNIEnv type is a pointer to store all JNI interface pointers. It is defined as follows:
typedef const struct JNINativeInterface *JNIEnv;
Virtual machine initialization function table, as shown in the following code, the first three entries are reserved for future compatibility with COM. Also, we keep some extra NULL entries near the beginning of the function table, for example, so that future class-related JNI operations can be added after FindClass instead of at the end of the table. Note that the function table can be shared between all JNI interface pointers.
First let's look at JNINativeInterface:
const struct JNINativeInterface ... = {
NULL,
NULL,
NULL,
NULL,
GetVersion,
DefineClass,
FindClass,
FromReflectedMethod,
FromReflectedField,
ToReflectedMethod,
GetSuperclass,
IsAssignableFrom,
ToReflectedField,
Throw,
ThrowNew,
ExceptionOccurred,
ExceptionDescribe,
ExceptionClear,
FatalError,
PushLocalFrame,
PopLocalFrame,
NewGlobalRef,
DeleteGlobalRef,
DeleteLocalRef,
IsSameObject,
NewLocalRef,
EnsureLocalCapacity,
AllocObject,
NewObject,
NewObjectV,
NewObjectA,
GetObjectClass,
IsInstanceOf,
GetMethodID,
CallObjectMethod,
CallObjectMethodV,
CallObjectMethodA,
CallBooleanMethod,
CallBooleanMethodV,
CallBooleanMethodA,
CallByteMethod,
CallByteMethodV,
CallByteMethodA,
CallCharMethod,
CallCharMethodV,
CallCharMethodA,
CallShortMethod,
CallShortMethodV,
CallShortMethodA,
CallIntMethod,
CallIntMethodV,
CallIntMethodA,
CallLongMethod,
CallLongMethodV,
CallLongMethodA,
CallFloatMethod,
CallFloatMethodV,
CallFloatMethodA,
CallDoubleMethod,
CallDoubleMethodV,
CallDoubleMethodA,
CallVoidMethod,
CallVoidMethodV,
CallVoidMethodA,
CallNonvirtualObjectMethod,
CallNonvirtualObjectMethodV,
CallNonvirtualObjectMethodA,
CallNonvirtualBooleanMethod,
CallNonvirtualBooleanMethodV,
CallNonvirtualBooleanMethodA,
CallNonvirtualByteMethod,
CallNonvirtualByteMethodV,
CallNonvirtualByteMethodA,
CallNonvirtualCharMethod,
CallNonvirtualCharMethodV,
CallNonvirtualCharMethodA,
CallNonvirtualShortMethod,
CallNonvirtualShortMethodV,
CallNonvirtualShortMethodA,
CallNonvirtualIntMethod,
CallNonvirtualIntMethodV,
CallNonvirtualIntMethodA,
CallNonvirtualLongMethod,
CallNonvirtualLongMethodV,
CallNonvirtualLongMethodA,
CallNonvirtualFloatMethod,
CallNonvirtualFloatMethodV,
CallNonvirtualFloatMethodA,
CallNonvirtualDoubleMethod,
CallNonvirtualDoubleMethodV,
CallNonvirtualDoubleMethodA,
CallNonvirtualVoidMethod,
CallNonvirtualVoidMethodV,
CallNonvirtualVoidMethodA,
GetFieldID,
GetObjectField,
GetBooleanField,
GetByteField,
GetCharField,
GetShortField,
GetIntField,
GetLongField,
GetFloatField,
GetDoubleField,
SetObjectField,
SetBooleanField,
SetByteField,
SetCharField,
SetShortField,
SetIntField,
SetLongField,
SetFloatField,
SetDoubleField,
GetStaticMethodID,
CallStaticObjectMethod,
CallStaticObjectMethodV,
CallStaticObjectMethodA,
CallStaticBooleanMethod,
CallStaticBooleanMethodV,
CallStaticBooleanMethodA,
CallStaticByteMethod,
CallStaticByteMethodV,
CallStaticByteMethodA,
CallStaticCharMethod,
CallStaticCharMethodV,
CallStaticCharMethodA,
CallStaticShortMethod,
CallStaticShortMethodV,
CallStaticShortMethodA,
CallStaticIntMethod,
CallStaticIntMethodV,
CallStaticIntMethodA,
CallStaticLongMethod,
CallStaticLongMethodV,
CallStaticLongMethodA,
CallStaticFloatMethod,
CallStaticFloatMethodV,
CallStaticFloatMethodA,
CallStaticDoubleMethod,
CallStaticDoubleMethodV,
CallStaticDoubleMethodA,
CallStaticVoidMethod,
CallStaticVoidMethodV,
CallStaticVoidMethodA,
GetStaticFieldID,
GetStaticObjectField,
GetStaticBooleanField,
GetStaticByteField,
GetStaticCharField,
GetStaticShortField,
GetStaticIntField,
GetStaticLongField,
GetStaticFloatField,
GetStaticDoubleField,
SetStaticObjectField,
SetStaticBooleanField,
SetStaticByteField,
SetStaticCharField,
SetStaticShortField,
SetStaticIntField,
SetStaticLongField,
SetStaticFloatField,
SetStaticDoubleField,
NewString,
GetStringLength,
GetStringChars,
ReleaseStringChars,
NewStringUTF,
GetStringUTFLength,
GetStringUTFChars,
ReleaseStringUTFChars,
GetArrayLength,
NewObjectArray,
GetObjectArrayElement,
SetObjectArrayElement,
NewBooleanArray,
NewByteArray,
NewCharArray,
NewShortArray,
NewIntArray,
NewLongArray,
NewFloatArray,
NewDoubleArray,
GetBooleanArrayElements,
GetByteArrayElements,
GetCharArrayElements,
GetShortArrayElements,
GetIntArrayElements,
GetLongArrayElements,
GetFloatArrayElements,
GetDoubleArrayElements,
ReleaseBooleanArrayElements,
ReleaseByteArrayElements,
ReleaseCharArrayElements,
ReleaseShortArrayElements,
ReleaseIntArrayElements,
ReleaseLongArrayElements,
ReleaseFloatArrayElements,
ReleaseDoubleArrayElements,
GetBooleanArrayRegion,
GetByteArrayRegion,
GetCharArrayRegion,
GetShortArrayRegion,
GetIntArrayRegion,
GetLongArrayRegion,
GetFloatArrayRegion,
GetDoubleArrayRegion,
SetBooleanArrayRegion,
SetByteArrayRegion,
SetCharArrayRegion,
SetShortArrayRegion,
SetIntArrayRegion,
SetLongArrayRegion,
SetFloatArrayRegion,
SetDoubleArrayRegion,
RegisterNatives,
UnregisterNatives,
MonitorEnter,
MonitorExit,
GetJavaVM,
GetStringRegion,
GetStringUTFRegion,
GetPrimitiveArrayCritical,
ReleasePrimitiveArrayCritical,
GetStringCritical,
ReleaseStringCritical,
NewWeakGlobalRef,
DeleteWeakGlobalRef,
ExceptionCheck,
NewDirectByteBuffer,
GetDirectBufferAddress,
GetDirectBufferCapacity,
GetObjectRefType
};
Below we will introduce in detail
2. Get JNI version information
In the JNIEnv pointer, there is a function to get the version of JNI:
jint GetVersion(JNIEnv *env);
This method mainly returns the version information of the local JNI method interface. The return value is different in different JDK environments, as follows:
- In JDK/JRE 1.1, returns 0x00010001
- In JDK/JRE 1.2, returns 0x00010002
- In JDK/JRE 1.3, returns 0x00010004
- In JDK/JRE 1.4, returns 0x00010006
The above numbers are not taken randomly by me. In fact, they have long been defined as a macro, as follows:
#define JNI_VERSION_1_1 0x00010001
#define JNI_VERSION_1_2 0x00010002
/* Error codes */
#define JNI_EDETACHED (-2) /* thread detached from the VM */
#define JNI_EVERSION (-3) /* JNI version error
SINCE JDK/JRE 1.4:
#define JNI_VERSION_1_4 0x00010004
SINCE JDK/JRE 1.6:
#define JNI_VERSION_1_6 0x00010006
3. Java class operation
(1), define class (load class)
jclass DefineClass(JNIEnv *env,const char* name,jobject loader,const jbyte *buf, jsize bufLen)
This function mainly loads the class from the buffer containing the data, which contains the original class data that is not referenced by the virtual machine when the class is called.
Entry explanation:
- env: JNI interface pointer
- name: The defined class name or interface name, the string has modefied UTF-8 encoding
- loader: assigned to the defined class loader
- buf: buffer containing .class file data
- bufLen: buffer length
Returns: Java class object, returns NULL when an error occurs
Possible exceptions thrown:
- If no Java class is specified, a ClassFormatError will be thrown
- If a class/interface is a superclass/superinterface of itself, a ClassCircularityError will be thrown
- If out of memory, an OutOfMemoryError will be thrown
- A SecurityException is thrown if one tries to define a class in a Java package
(2), search class
jclass FindClass(JNIEnv *env,const char *name);
There are two cases here, one is JDK release1.1, and the other is JDK release 1.2. From JDK release 1.1, this function loads a locally defined class, which searches the directories and zip files in the CLASSPATH environment variable for a class with a specific name. Since Java 2 release 1.2, the Java security model allows non-system class loading and calling native methods. FindClass defines the class loading associated with the current native method, that is, the class loading class of the class declaring the native method. If the native method belongs to a system class, no class loader is involved; otherwise, the appropriate class loading is invoked to load and link the specified class. Starting with Java 2 SDK 1.2, when calling FindClass through the calling interface, there is no current native method or associated class loader. In this case, use the result of ClassLoader.getSystemClassLoader. This is the class loader that the virtual machine creates for the application and is able to find the classes listed in the java.class.path property.
Entry explanation:
- env: JNI interface pointer
- name: A fully qualified class name, which includes "package name" + "/" + class name. For example: such as java.lang.String, the parameter is java/lang/String; if the class name starts with [, an array class will be returned. For example, the signature of the array class is java.lang.Object[], and the parameter should be "[Ljava/lang/Object"
return:
- Returns the corresponding fully qualified class object, when the class cannot be found, returns NULL
Possible exceptions thrown:
- If no Java class is specified, a ClassFormatError will be thrown
- If a class/interface is a superclass/superinterface of itself, a ClassCircularityError will be thrown
- If no definition for the class/interface is found, NoClassDefFoundError is thrown
- If out of memory, an OutOfMemoryError will be thrown
(3), find the parent class
jclass GetSuperclass(JNIEnv *env,jclass clazz);
If clazz is not of class Object, this function will return a Class object representing the parent class of this clazz, if the class is Object, or clazz represents an interface, this function will return NULL.
Entry explanation:
- env: JNI interface pointer
- clazz: Java Class class
return:
- Returns the clazz's parent class if it has one, or NULL if it does not
(4), safe conversion
jboolean IsAssignableFrom(JNIEnv *env,jclass clazz1,jclass clazz2);
Determine whether the object of clazz1 can be safely converted to the object of clazz2
Entry explanation:
- env: JNI interface pointer
- clazz1: Java's Class class, that is, the class that needs to be converted
- clazz2: Java's Class class, that is, the class that needs to be converted into a target
return:
Returns JNI_TRUE if any of the following conditions are true:
- If clazz1 and clazz2 are the same Java class.
- If clazz1 is a subclass of clazz2
- If clazz1 is the implementation class of clazz2 interface
4. Abnormal operation
(1), throwing an exception
jint Throw(JNIEnv *env,jthrowable obj);
Pass in a jthrowable object, and throw it in JNI:
Entry explanation:
- env: JNI interface pointer
- jthrowable: a Java java.lang.Throwable object
return:
- Returns 0 on success, and a negative number on failure.
Possible exceptions thrown:
- Throws a java.lang.Throwable object
(2) Construct a new exception and throw it
jint ThrowNew(JNIEnv *env,jclass clazz,const char* message);
Pass in a message, use it to construct an exception and throw it.
Entry explanation:
- env: JNI interface pointer
- jthrowable: a Java java.lang.Throwable object
- message: The message used to construct a java.lang.Throwable object, the string is encoded in modified UTF-8
return:
- Returns 0 on success, a negative number on failure
Possible exceptions thrown:
- Throws a newly constructed java.lang.Throwable object
(3) Check whether an exception occurs and throw an exception
jthrowable ExceptionOccurred(JNIEnv *env);
Check whether an exception has occurred, and if so, return a reference to the exception (before calling the ExceptionClear() function, or before Java handles the exception), and return NULL if no exception occurs.
Entry explanation:
- env: JNI interface pointer
return:
- jthrowable's exception reference or NULL
(4) Print the abnormal stack information
void ExceptionDescribe(JNIEnv *env)
Print the exception's stack trace.
Entry explanation:
- env: JNI interface pointer
(5) Clear the exception stack information
void ExceptionClear(JNIEnv *env);
Clears the exception being thrown. If no exception is currently thrown, this function has no effect.
Entry explanation:
- env: JNI interface pointer
(6), fatal exception
void FatalError(JNIEnv *env,const char* msg);
A fatal exception is used to output an exception message and terminate the current VM instance, that is, exit the program.
Entry explanation:
- env: JNI interface pointer
- msg: the error message of the exception, the string is encoded in modified UTF-8
(7), just check whether an exception occurs
jboolean ExceptionCheck(JNIEnv *env);
Checks whether an exception has occurred, and returns JNI_TRUE if an exception has occurred, or JNI_FALSE otherwise.
Entry explanation:
- env: JNI interface pointer
return:
- Returns JNI_TRUE if an exception has occurred, or JNI_FALSE if no exception has occurred
5. Global references and local references
(1) Create a global reference
jobject NewGlobalRef(JNIEnv *env,object obj);
Create a global reference to the object obj, obj can be a global or local reference. Global references must be explicitly handled via DeleteGlobalRef().
Parameter explanation:
- env: JNI interface pointer
- obj: object object
return:
- Global reference to jobject, return NULL if out of memory
(2), delete the global reference
void DeleteGlobalRef(JNIEnv *env,jobject globalRef);
Remove global references.
Parameter explanation:
- env: JNI interface pointer
- globalRef: the global reference that needs to be deleted
(3) Delete local references
Local references are only valid during the lifetime of the native interface call, and they are automatically released when the native method returns. Each local reference will consume a certain amount of virtual machine resources. Although local references can be automatically destroyed, programmers also need to be careful not to over-allocate local references in local methods. Excessive allocation of local references will cause the virtual machine to memory when executing local methods overflow.
void DeleteLocalRef(JNIEnv *env, jobject localRef);
Delete local references via localRef.
parameter explanation
- env: JNI interface pointer
- localRef: the local reference that needs to be deleted
JDK/JRE 1.1 provides the above DeleteLocalRef function so that programmers can manually delete local references.
Starting from JDK/JRE 1.2, a set of life cycle management functions are provided, which are the following four functions.
(4) Set the capacity of local variables
jint EnsureLocalCapacity(JNIEnv *env,jint capacity);
In the current thread, limit the number of local references created by passing in a capacity, capacity. Returns 0 on success, otherwise returns a negative number and throws an OutOfMemoryError. The VM automatically ensures that at least 16 local references can be created.
parameter explanation
- env: JNI interface pointer
- capacity—Capacity
return:
- Success returns 0, failure returns a negative number, and an OutOfMemoryError will be thrown
For backward compatibility, if the virtual machine creates local references that exceed capacity. The VM calls FatalError to ensure that no more local references can be created. (If it is in debug mode, the virtual machine will issue a warning to the user and prompt that more local references have been created. In JDK, the programmer can provide the -verbose: jni command line option to open this message)
(5) Create a new frame on the old one
jint PushLocalFram(JNIEnv *env ,jint capacity);
In the case that the local variable capacity has been set, re-create a local variable container. Success returns 0, failure returns a negative number and throws an OutOfMemoryError exception.
Note: In the current local frame, the local references created by the previous local frame are still valid
parameter explanation
- env: JNI interface pointer
- capacity—Capacity
(6), release a local reference
jobject PopLocalFrame(JNIEnv *env,jobject result)
Pops the current local reference frame and releases all local references. Returns the local reference corresponding to the given result object at the previous local reference frame. If you do not need to return any references, set result to NULL.
parameter explanation
- env: JNI interface pointer
- result: the local reference that needs to be released
(7) Create a local reference
jobject NewLocalRef(JNIEnv *env,jobject ref);
Create a local reference from ref. ref can be a global or local reference, if ref is NULL, returns NULL.
parameter explanation
- env: JNI interface pointer
- ref: You can try local references or global references.
(8), weak global reference
A weak global reference is a special kind of global reference. Unlike normal global references, a weak global reference allows the underlying Java object to be garbage collected. Weak global references can be applied wherever global or local references are used. When the garbage collector runs, it will free the underlying variables if the object is only referenced by weak references. A weak global reference to a freed object is equivalent to NULL. Programmers can check whether a weak global refers to a freed object by using isSampleObject to compare the weak reference to NULL. Weak global references in JNI are a simplified version of Java weak references, available in the Java platform API.
When the native method is running, the garbage collector may be working, and the object pointed to by the weak reference may be released at any time. Weak global references can be applied anywhere global references are used, which is generally not a good idea to do so because they can become NULL inadvertently.
When IsSampleObject can identify whether a weak global reference points to a released object, but this does not prevent the object from being released immediately after being detected. This means that programmers cannot rely on this method to identify whether a weak global reference can be used in subsequent JNI function calls.
If you want to solve the above problems, it is recommended to use the JNI function NewLocalRef or NewGlobalRef to use standard global or local references to point to the same object. These functions return NULL if the exclusive has been released. Otherwise, a strong reference is returned (so that the object will not be released). When access to this object is no longer needed, new references must be explicitly deleted.
1. Create a global weak reference
jweak NewWeakGlobalRef(JNIEnv *env,jobject obj);
Create a new weak global reference. Returns NULL if obj points to NULL. If the VM memory overflows, an exception OutOfMemoryError will be thrown.
parameter explanation
- env: JNI interface pointer
- obj: reference object
return:
- global weak reference
2. Delete the global weak reference
void DeleteWeakGlobalRef(JNIEnv *env,jweak obj);
The VM deletes the corresponding resource according to the given weak global reference.
parameter explanation
- env: JNI interface pointer
- obj: the weak global reference that will be deleted
Six, object operation
(1) Create a Java object directly
jobject AllocObject(JNIEnv *env,jclass clazz);
Allocates a new Java object without resorting to any constructor, returning a reference to the object.
Parameter explanation:
- env: JNI interface pointer
- clazz:: Java class object
return:
- Returns a Java object, or NULL if the object could not be created.
abnormal:
- If the class is an interface or an abstract class, an InstantiationException is thrown
- If it is out of memory, OutOfMemoryError is thrown
(2) Create a Java object according to a constructor
jobject NewObject(JNIEnv *env,jclass clazz,jmethodID methodID,...);
jobject NewObjectA(JNIEnv *env,jclass clazz,jmethodID methodID,const jvalue *args);
jobject NewObjectV(JNIEnv *env,jclass clazz,jmethodID methodID,va_list args);
Constructs a new Java object, methodID indicates that a constructor needs to be called. This ID must be obtained by calling GetMethodID(), GetMethodID() is the function name, and void (V) is the return value. The clazz parameter cannot point to an array class.
- NewObject: It is necessary to put the input parameters of all constructors after the parameter methodID. NewObject() takes these parameters and passes them to the Java constructor that needs to be called
- NewObjectA: After methodID, a parameter array of type jvalue—args is placed, which stores all parameters that need to be passed to the constructor. NewObjectA() receives all the parameters in this array and passes them in order to the Java method that needs to be called.
- NewObjectV: After the methodID, an args of type va_list is placed, and the parameters store all the parameters that need to be passed to the constructor. NewObjectv() receives all parameters and passes them in order to the Java method that needs to be called.
Parameter explanation:
- env: JNI interface pointer
- clazz::Java class
- methodID: the method ID of the constructor
Additional parameters:
- Additional parameters of NewObject: arguments are the parameters of the constructor
- Additional parameters for NewObjectA: args is an array of parameters for the constructor
- Additional parameters of NewObjectV: args is the parameter list of the constructor
return:
- the Java object, or NULL if the object could not be created
abnormal:
- If the incoming class is an interface or an abstract class, an InstantiationException is thrown
- Throw OutOfMemoryError if out of memory
- All exceptions are thrown through the constructor
(3) Get the "class" of an object
jclass GetObjectClass(JNIEnv *env,object obj);
Returns the class corresponding to obj.
parameter explanation
- env: JNI interface pointer
- obj: Java object, cannot be NULL
return:
- Returns a Java "class" object
(4) Get the "type" of an object
jobjectRefType GetObjectRefType(JNIEnv *env,jobject obj);
Returns the type of the object pointed to by the obj parameter. The parameter obj can be a local variable, a global variable or a global reference.
parameter explanation
- env: JNI interface pointer
- obj: local, global or weak global reference
return:
- JNIInvalidRefType=0: indicates that the obj parameter is not a valid reference type
- JNILocalRefType=1: indicates that the obj parameter is a local variable type
- JNIGlobalRefType=2: indicates that the obj parameter is a global variable type
- JNIWeakGlobalRefType=3: indicates that the obj parameter is a weak global effective reference
An invalid citation is a citation without a citation. In other words, the pointer of obj does not point to the address in memory when the function was created, or has returned from the JNI function. So NULL is an invalid reference. And GetObjectRefType(env, NULL) will return type is JNIInvalidRefType. But what the null reference returns is not JNIInvalidRefType, but the reference type when it was created.
PS: This function cannot be called when the reference is being deleted
(5) Determine whether an object is a subclass of a "class"
jboolean IsInstanceOf(JNIEnv *env, jobject obj,jclass clazz);
Tests whether obj is an instance of clazz.
parameter:
- env: JNI interface pointer
- obj: a Java object
- clazz: a Java class
return:
Returns JNI_TRUE if obj is an instance of clazz; otherwise returns JNI_FALSE; an empty object can be an instance of any class.
(6) Determine whether two references point to the same reference
jboolean IsSampleObject(JNIEnv *env,jobject ref1,jobject ref2);
Determines whether two references point to the same object.
Parameter explanation:
- env: JNI interface pointer
- ref1: Java object
- ref2: Java object
return:
- If the same class object, return JNI_TRUE; otherwise, return JNI_FALSE;
(7), return attribute id
jfieldID GetFieldID(JNIEnv *env,jclass clazz,const char *name,const char *sig);
Get the non-static attribute id of a class. The corresponding attribute is determined by the method attribute name and the signature of the attribute (that is, the type of the attribute). By retrieving this attribute ID, we can call Get <type>Field and Set <type>Field, which are our commonly used get and set methods.
Parameter explanation:
- env: JNI interface pointer
- clazz: a Java class object
- name: attribute name ending with "0" and the character type is "utf-8"
- sig: attribute signature ending with "0" and the character type is "utf-8"
return
- The attribute corresponds to the ID, and returns NULL if the operation fails
abnormal:
- Throws NoSuchFieldError if the specified property cannot be found
- Throws ExceptionInitializerError if class initialization fails
- If out of memory, throw OutOfMemoryError
PS: GetFieldID() may cause uninitialized classes to start to initialize. At the same time, you cannot use GetFieldID() to get the length of the array, but GetArrayLength() should be used.
(8), return attribute id series
NativeType GetField(JNIEnv *env,jobject obj,jfieldID fielD);
Returns the value of a non-static property of a class, shorthand for a set of functions, as follows:
jobject GetObjectField(JNIEnv *env,jobject obj,jfieldID fielD)
jboolean GetBooleanField(JNIEnv *env,jobject obj,jfieldID fielD)
jbyte GetByteField(JNIEnv *env,jobject obj,jfieldID fielD)
jchar GetCharField(JNIEnv *env,jobject obj,jfieldID fielD)
jshort GetShortField(JNIEnv *env,jobject obj,jfieldID fielD)
jint GetIntField(JNIEnv *env,jobject obj,jfieldID fielD)
jlong GetLongField(JNIEnv *env,jobject obj,jfieldID fielD)
jfloat GetFloatField(JNIEnv *env,jobject obj,jfieldID fielD)
jdouble GetDoubleField(JNIEnv *env,jobject obj,jfieldID fielD)
Parameter explanation:
- env: JNI interface pointer
- obj: Java object, cannot be empty
- fieldID: a valid fieldID
return:
- The value of the corresponding attribute
(9), set the attribute id series
void Set<type>Field(JNIEnv *env,jobject obj,jfieldID fieldID,NativeType value)
Sets the value of a non-static property of a class. Among them, which attribute is determined by GetFieldID(). This is shorthand for a set of functions, as follows:
void SetObjectField(jobject)
void SetBooleanField(jboolean)
void SetByteField(jbyte)
void SetCharField(jchar)
void SetShortField(jshort)
void SetIntField(jint)
void SetLongField(jlong)
void SetFloatField(jfloat)
void SetDoubleField(jdouble)
Parameter explanation:
- env: JNI interface pointer
- obj: Java object, cannot be empty
- fieldID: a valid field ID
- value: the new value of the attribute
(10), get a method id of a class
jmethodID GetMethodID(JNIEnv *env,jclass clazz,const char*name,const char* sig);
Returns the method ID of a class or interface, which can be defined in the parent class of clazz and then inherited by clazz. We identify a method based on its name and signature.
GetMethodID () will cause the class that has not been initialized to be initialized.
If you want to get the ID of the constructor, provide init as the method name and void (V) as the return type.
Parameter explanation:
- env: JNI interface pointer
- clazz: Java class object
- name: method name that ends with 0 and is a string of "utf-8"
- sig: method signature that ends with 0 and is a string of "utf-8"
return:
- Returns a method ID, if the specified method is not found, it returns NULL
abnormal:
- If the specified method cannot be found, NoSuchMethodError is thrown
- If initialization fails, ExceptionInInitializerError is thrown
- If there is not enough memory, an OutOfMemoryError is thrown
(11), calling a non-static method "series" of a Java instance
NativeType Call<type>Method(JNIEnv *env,jobject obj,jmethodID methodID,...);
NativeType Call<type>MethodA(JNIEnv *env,jobjct obj,jmethodID methodID ,const jvalue *args);
NativeType Call<type>MethodV(JNEnv *env,jobject obj,jmethodID methodID,va_list args);
These columns are all calling a non-static method of a Java object in native, and the difference between them is that they pass parameters differently. It is to specify a certain method of the corresponding Java object according to the method ID. The methodID parameter needs to be obtained by calling GetMethodID().
When a "private" function or constructor needs to be called, the methodID must be a method of the obj class, not a method of its parent class.
Let's take a look at their differences
- CallMethod: You need to put the input parameters of the method after the parameter methodID. CallMethod() actually passes these parameters to the Java method that needs to be called.
- CallMethodA: Behind the methodID, there is an args array of type jvalue, which stores all the parameters that need to be passed to the constructor. CallMethodA() receives the parameters in this array and passes them to the corresponding Java method in order
- CallMethodV: Behind the methodID, there is a parameter args of type Wieva_list, which stores all the parameters that need to be passed to the constructor. CallMethodV() receives all parameters and passes them in order to the Java method that needs to be called.
Call<type>Method Routine Name Native Type
CallVoidMethod()
CallVoidMethodA() void
CallVoidMethodV()
CallObjectMethod()
CallObjectMethodA() jobject
CallObjectMethodV()
CallBooleanMethod()
CallBooleanMethodA() jboolean
CallBooleanMethodV()
CallByteMethod()
CallByteMethodA() jbyte
CallByteMethodV()
CallCharMethod()
CallCharMethodA() jchar
CallCharMethodV()
CallShortMethod()
CallShortMethodA() jshort
CallShortMethodV()
CallIntMethod()
CallIntMethodA() jint
CallIntMethodV()
CallLongMethod()
CallLongMethodA()
CallLongMethodV()
CallFloatMethod()
CallFloatMethodA() jlong
CallFloatMethodV()
CallDoubleMethod()
CallDoubleMethodA() jfloat
CallDoubleMethodV()
Parameter explanation:
- env: JNI interface pointer
- obj: the corresponding Java object
- methodID: the method id of a method
return:
- Returns the result corresponding to calling the Java method
abnormal:
- An exception occurs during the execution of a Java method.
(12), calling a non-abstract method of a class
Call the instance method in the parent class, as follows:
CallNonvirtual<type>Method
CallNonvirtual<type>MethodA
CallNonvirtual<type>MethodV
details as follows:
NativeType CallNonvirtual<Type>Method(JNIEnv *env,jobject obj,jclass clazz,jmethodID methodID,....);
NativeType CallNonvirtual<Type>MethodA(JNIEnv *env,jobject obj,jclass clazz,jmethodID methodID,const jvalue *args);
NativeType CallNonvirtual<type>MethodV(JNIEnv *env, jobject obj,
jclass clazz, jmethodID methodID, va_list args);
This series of operations is to call the non-static method of the instance of the Java object according to the specific class and its method ID. The methodID parameter needs to be obtained by calling GetMethodID().
CallNonvirtual<Type>Method and Call<type>Method are different, where CallNonvirtual<Type>Method is based on "class", and Call<type>Method is based on class object. So the input parameter of CallNonvirtual<Type>Method is clazz, methodID must come from the class of obi, not its parent class.
Let's take a look at their differences
- CallNonvirtual<type>Method : You need to put the input parameters of the method after the parameter methodID. CallNonvirtual<type>Method() actually passes these parameters to the Java method that needs to be called.
- CallNonvirtual<type>Method: Behind the methodID, there is an args array of type jvalue, which stores all the parameters that need to be passed to the constructor. CallNonvirtual<type>Method() receives the parameters in this array and passes them to the corresponding Java method in order
- CallNonvirtual<type>MethodV: Behind the methodID, there is a parameter args of type Wieva_list, which stores all the parameters that need to be passed to the constructor. CallNonvirtual<type>MethodV() receives all parameters and passes them in order to the Java method that needs to be called.
Expand the above series of methods as follows:
CallNonvirtual<type>Method Routine Name Native Type
CallNonvirtualVoidMethod()
CallNonvirtualVoidMethodA() void
CallNonvirtualVoidMethodV()
CallNonvirtualObjectMethod()
CallNonvirtualObjectMethodA() jobject
CallNonvirtualObjectMethodV()
CallNonvirtualBooleanMethod()
CallNonvirtualBooleanMethodA() jboolean
CallNonvirtualBooleanMethodV()
CallNonvirtualByteMethod()
CallNonvirtualByteMethodA() jbyte
CallNonvirtualByteMethodV()
CallNonvirtualCharMethod()
CallNonvirtualCharMethodA() jchar
CallNonvirtualCharMethodV()
CallNonvirtualShortMethod()
CallNonvirtualShortMethodA() jshort
CallNonvirtualShortMethodV()
CallNonvirtualIntMethod()
CallNonvirtualIntMethodA() jint
CallNonvirtualIntMethodV()
CallNonvirtualLongMethod()
CallNonvirtualLongMethodA() jlong
CallNonvirtualLongMethodV()
CallNonvirtualFloatMethod()
CallNonvirtualFloatMethodA() jfloat
CallNonvirtualFloatMethodV()
CallNonvirtualDoubleMethod()
CallNonvirtualDoubleMethodA() jdouble
CallNonvirtualDoubleMethodV()
Parameter explanation:
- env: JNI interface pointer
- obj: Java object
- clazz: Java class
- methodID: Method ID
return:
- The result of calling the Java method
Throw an exception:
- Exceptions that may occur during the execution of a Java method
(13), get static attributes
jfieldID GetStaticFieldID(JNIEnv *env,jclass clazz,const char* name,const char *sig);
Obtain a static attribute ID of a class, and determine which attribute it is based on the attribute name and label. GetStaticField() and SetStaticField() operate on properties by using the property ID. If the class has not been initialized, calling GetStaticFieldID() directly will cause the class to be initialized.
Parameter explanation:
- env: JNI interface pointer
- clazz: Java class
- name: The attribute name of the static attribute, which is a string encoded in "utf-8" and terminated by 0.
- sig: The signature of the attribute, which is a string encoded in "utf-8" and terminated by 0.
return:
Returns the static attribute ID, or NULL if the specified static attribute cannot be found
abnormal:
- Throws NoSuchFieldError if the specified static property cannot be found
- ExceptionInInitializerError is thrown if the class fails to initialize
- If there is not enough memory, an OutOfMemoryError is thrown
(14), get the static attribute series
NativeType GetStatic<type>Field(JNIEnv *env,jclass clazz,jfieldID fieldID);
This series returns the value of a static property of an object. The ID of the static attribute can be obtained through GetStaticFieldID(). With this ID, we can obtain this and operate on it.
The function name and return value of the function are shown below, so you only need to replace the class in GetStatic<type>Field with the Java type of the field or the actual static field accessor in the table. and replace NativeType with the corresponding native type:
GetStatic<type>Field Routine Name Native Type
GetStaticObjectField() jobject
GetStaticBooleanField() jboolean
GetStaticByteField() jbyte
GetStaticCharField() jchar
GetStaticShortField() jshort
GetStaticIntField() jint
GetStaticLongField() jlong
GetStaticFloatField() jfloat
GetStaticDoubleField() jdouble
Parameter explanation:
- env: JNI interface pointer
- clazz: Java class
- field: static attribute ID
return:
- return static property
(15), set the static attribute series
void SetStatic<type>Field(JNIEnv *env,jclass clazz,jfieldID fieldID,NativeType value);
This series is to set the value of the static property of the class. The ID of a static field can be obtained through GetStaticFieldID().
The function name and its value are introduced in detail below. You can set the static property in Java through SetStatic<type> and the NativeType passed in.
SetStatic<type>Field Routine Name NativeType
SetStaticObjectField() jobject
SetStaticBooleanField() jboolean
SetStaticByteField() jbyte
SetStaticCharField() jchar
SetStaticShortField() jshort
SetStaticIntField() jint
SetStaticLongField() jlong
SetStaticFloatField() jfloat
SetStaticDoubleField() jdouble
Parameter explanation:
- env: JNI interface pointer
- clazz: Java class
- field: static attribute ID
- value: set value
(16), get the static function ID
jmethodID GetStaticMethodID(JNIEnv *env,jclass clazz,const char *name,const char sig);
Returns the static method ID of the class, which method is identified by its method name and signature. If the class has not been initialized, calling GetStaticMethodID() will cause the class to be initialized.
Parameter explanation:
- env: JNI interface pointer
- clazz: Java class
- name: The method name of the static method, encoded in "utf-8", and terminated by 0
- sig: method signature, encoded in "utf-8", and a 0-terminated string
return:
- Returns the method ID, or NULL if the operation failed
abnormal:
- If no corresponding static method is found, NoSuchMethodError is thrown
- Throws ExceptionInInitializerError if class initialization fails
- Throws OutOfMemoryError if the system is out of memory
(17), calling static function series
NativeType CallStatic<type>Method(JNIEnv *env,jclass clazz,jmethodID methodID,...);
NativeType CallStatic<type>MethodA(JNIEnv *env,jclass clazz,jmethodID methodID,... jvalue *args);
NativeType CallStatic<type>MethodV(JNIEnv *env,jclass,jmethodID methodid, va_list args)
According to the specified method ID, you can operate the static method of the Java object. The methodID can be obtained through GetStaticMethodID(). The ID of the method must be clazz's, not the method ID of its parent class.
The following is the detailed method:
CallStatic<type>Method Routine Name Native Type
CallStaticVoidMethod()
CallStaticVoidMethodA() void
CallStaticVoidMethodV()
CallStaticObjectMethod()
CallStaticObjectMethodA() jobject
CallStaticObjectMethodV()
CallStaticBooleanMethod()
CallStaticBooleanMethodA() jboolean
CallStaticBooleanMethodV()
CallStaticByteMethod()
CallStaticByteMethodA() jbyte
CallStaticByteMethodV()
CallStaticCharMethod()
CallStaticCharMethodA() jchar
CallStaticCharMethodV()
CallStaticShortMethod()
CallStaticShortMethodA() jshort
CallStaticShortMethodV()
CallStaticIntMethod()
CallStaticIntMethodA() jint
CallStaticIntMethodV()
CallStaticLongMethod()
CallStaticLongMethodA() jlong
CallStaticLongMethodV()
CallStaticFloatMethod()
CallStaticFloatMethodA() jfloat
CallStaticFloatMethodV()
CallStaticDoubleMethod()
CallStaticDoubleMethodA() jdouble
CallStaticDoubleMethodV()
Parameter explanation:
- env: JNI interface pointer
- clazz: Java class
- methodID: static method ID
return:
- Returns the calling method of a static Java method
abnormal:
- Exception thrown during execution of Java method
Seven, string operation
(1), create a string
jstring NewString(JNIEnv *env,const jchar *unicodeChars,jszie len);
Parameter explanation:
- env: JNI interface pointer
- unicodeChars: pointer to Unicode character string
- len: the length of the unicode string
return:
- Returns a Java string object, or NULL if the string cannot be created
abnormal:
- Throws OutOfMemoryError if out of memory
(2) Get the length of the string
jsize GetStringLength(JNIEnv *env,jstring string);
Returns the length of the Java string (the number of unicode characters)
Parameter explanation:
- env: JNI interface pointer
- string: Java string object
return:
- Returns the length of a Java String
(3) Obtain the pointer of the string
const jchar* GetStringChar(JNIEnv *env,jstring string , jboolean *isCopy);
Returns a pointer to the UNICODE character array of the string, which is valid until the ReleaseStringchars() function is called.
If isCopy is non-null, set isCopy to JNI_TRUE after the copy is complete. Set to JNI_FALSE if no replication.
Parameter explanation:
- env: JNI interface pointer
- string: Java string object
- isCopy: pointer to boolean value
return:
- Returns a pointer to a unicode string, or NULL if the operation fails
(4), release the string
void ReleaseStringChars(JNIEnv *env,jstring string,const jchar *chars);
Through the VM, native code will no longer access chars. The parameter chars is a pointer. It can be obtained through the GetStringChars() function.
Parameter explanation:
- env: JNI interface pointer
- string: Java string object
- chars: pointer to Unicode character string
(5) Create a UTF-8 string
jstring NewStringUTF(JNIEnv *env,const char *bytes);
Create a UTF-8 string.
Parameter explanation:
- env: JNI interface pointer
- bytes: pointer to UTF-8 string
return:
- A Java String object, or NULL if the string could not be constructed.
abnormal:
- Throws OutOfMemoryError if the system is out of memory
(6) Get the length of a UTF-8 string
jsize GetStringUTFLength(JNIEnv *env,jstring string);
Returns the UTF-8 length of the string in bytes.
Parameter explanation:
- env: JNI interface pointer
- String: Java string object
return:
- UTF-8 length of the string
(7), Get the pointer of StringUTFChars
const char *GetStringUFTChars(JNIEnv *env, jString string, jboolean *isCopy);
Returns a pointer to a UTF-8 character array, which remains valid unless the array is released by the ReleaseStringUTFChars() function call.
If isCopy is not NULL, *isCopy is set to JNI_TRUE after the assignment is complete. Set to JNI_FALSE if not copied.
Parameter explanation:
- env: JNI interface pointer
- String: Java string object
- isCopy: pointer to boolean value
return:
- Pointer to a UTF-8 string, or NULL if the operation failed.
(8), release UTFChars
void ReleaseStringUTFChars(JNIEnv *env,jstring string,const char *urf)
Through the virtual machine, the native code no longer accesses utf. utf is a pointer, which can be obtained by calling GetStringUTFChars().
Parameter explanation:
- env: JNI interface pointer
- string: Java string object
- utf: pointer to utf-8 string
Note: In JDK/JRE 1.1, programmers can get basic type array elements in user-supplied buffers. Starting from JDK/JRE1.2, additional methods are provided that allow Unicode characters (UTF -16 encoding) or UTF-8 characters. These methods are as follows:
(9), JRE1.2 new string operation method
1. Intercept a string
void GetStringRegion(JNIEnv *env,jstring str,jsize start,jsize len,jchar *buf)
Intercept the length of len from the start position in str (Unicode character) and place it in buf. Throws StringIndexOutOfBoundsException if out of bounds.
2. Intercept a string and convert it to UTF-8 format
void GetStringUTFRegion(JNIEnv *env,jstring str,jsize start ,jsize len,char *buf);
Intercept str (Unicode string) with a length of len from the start position and convert it to UTF-8 encoding, and then store the result in buf.
3. Intercept a string and convert it to UTF-8 format
const jchar * GetStringCritical(JNIEnv *env,jstring string,jboolean *isCopy);
void ReleaseStringCritical(JNIEnv *env,jstring string,cost jchar * carray);
The above two functions are somewhat similar to the GetStringChars() and ReleaseStringChars() functions. The virtual machine returns a pointer to the string element if possible; otherwise, a copied copy.
GetStringChars () and ReleaseStringChars () These two functions have great limitations. When using these two functions, the code between these two functions cannot call any native functions or JNI functions that make the thread block or wait for other threads of the JVM. With these restrictions, the JVM can disable GC when a native method holds a pointer to a string obtained from GetStringCritical. When GC is disabled, any thread that initiates GC will be blocked. However, any native code between the two functions GetStringChars() and ReleaseStringChars() cannot execute calls that cause blocking or allocate memory in the JVM for new objects. Otherwise, the JVM may deadlock, imagine this scenario:
- Only when the GC triggered by the current thread finishes blocking and releases the GC, can the GC initiated by other threads be released from the blocking and continue to execute.
- During this process, the current thread will always be blocked, because any blocking call needs to acquire a lock that is being held by other threads, while other threads are waiting for GC.
Alternate iterative calls of GetStringChars() and ReleaseStringChars() are safe, in which case their use must be strictly ordered. Moreover, we must remember to check whether its return value is NULL due to memory overflow. Because the JVM still has the possibility of data copying when executing the GetStringChars() function, especially when the array stored by the JVM in memory is discontinuous, in order to return a pointer to a continuous memory space, the JVM must copy all data.
In summary, to avoid deadlocks, do not call any JNI functions between GetStringChars() and ReleaseStringChars().
Eight, array operation
(1) Get the length of the array
jsize GetArrayLength(JNIEnv *env,jarray array)
Returns the length of the array.
Parameter explanation:
- env: JNI interface pointer
- array: Java array
return:
- the length of the array
(2) Create an array of objects
jobjectArray NewObjectArray(JNIEnv *env,jsize length,jclass elementClass, jobject initialElement);
Creates a new array of objects whose elements are of type elementClass and whose default value is initialElement.
Parameter explanation:
- env: JNI interface pointer
- length: array size
- elementClass: array element class
- initialElement: the initial value of the array element
return:
- Java array object, or NULL if the array cannot be constructed
abnormal:
- Throws OutOfMemoryError if out of memory
(3) Get an element in the array element
jobject GetObjectArrayElement(JNIEnv *env,jobjectArray array,jsize index);
Returns the element at a position within the element.
Parameter explanation:
- env: JNI interface pointer
- array: Java array
- index: array subscript
return:
- java object
abnormal:
- If the index subscript is not a valid subscript, an ArrayIndexOutOfBoundsException will be thrown
(4), set the value of an element in the array
void SetObjectArrayElement(JNIEnv *env,jobjectArray array,jsize index,jobject value);
Sets the subscript to the value of the index element.
Parameter explanation:
- env: JNI interface pointer
- array: Java array
- index: array subscript
- value: the new value of the array element
abnormal:
- If index is not a valid subscript, an ArrayIndexOutOfBoundsException will be thrown
- ArrayStoreException will be thrown if value is not a subclass of the element class
(5) Create a series of basic type arrays
ArrayType New<PrimitiveType>Array(JNIEnv *env,jsize length);
A sequence of operations for constructing array objects of primitive types. The creation functions for arrays of specific primitive types are described below. You can replace New<PrimitiveType>Array with an actual primitive type array creation function, and then replace ArrayType with the corresponding array type.
New<PrimitiveType>Array Routines Array Type
NewBooleanArray() jbooleanArray
NewByteArray() jbyteArray
NewCharArray() jcharArray
NewShortArray() jshortArray
NewIntArray() jintArray
NewLongArray() jlongArray
NewFloatArray() jfloatArray
NewDoubleArray() jdoubleArray
Parameter explanation:
- env: JNI interface pointer
- length: array length
return:
- The Java array, or NULL if the array could not be created.
(6) Obtain the medium array pointer series of the basic type array
NativeType * Get<PrimitiveType>ArrayElements(JNIEnv *env,ArrayType array,jboolean * isCopy);
A set of functions that return array bodies of primitive types. The result will remain valid until the corresponding Release<PrimitiveType>ArrayElements() function is called. Since the returned array may be a copy of the Java array, changes to the returned array do not have to be reflected in the primitive array until the Release<PrimitiveType>ArrayElements() function is called.
If isCopy is not NULL, *isCopy is set to JNI_TRUE after the copy is complete. Set to JNI_FALSE if not copied.
Specific functions for specific primitive type array elements are described below:
- Replace Get<PrimitiveType>ArrayElements with a function of some actual primitive> type in the table
- Replace ArrayType with the corresponding array type
- Replace NativeType with local variable
Regardless of how the Boolean array is always represented in the Java virtual machine, GetBooleanArrayElements() will always return a pointer of jboolean type, where each byte represents an element (open package representation). Arrays of all other types are guaranteed to be contiguous in memory.
Get<PrimitiveType>ArrayElements Routines Array Type Native Type
GetBooleanArrayElements() jbooleanArray jboolean
GetByteArrayElements() jbyteArray jbyte
GetCharArrayElements() jcharArray jchar
GetShortArrayElements() jshortArray jshort
GetIntArrayElements() jintArray jint
GetLongArrayElements() jlongArray jlong
GetFloatArrayElements() jfloatArray jfloat
GetDoubleArrayElements() jdoubleArray jdouble
Parameter explanation:
- env: JNI interface pointer
- array: Java array
- isCopy: pointer to boolean value
return:
- Returns a pointer to an element of the array, or NULL if the operation failed
(7) Release the array series of basic types
void Release<PrimitiveType>ArrayElements(JNIEnv *env,ArrayType array,NativeType *elems,jint mode);
Notify the virtual machine that Native no longer accesses the elements of the array. The elems parameter is a pointer returned by the corresponding Get<PrimitiveType> ArrayElements() function array element. This function copies all transformations on elems to the original array elements, if necessary. The mode parameter provides how the array buffer should be freed. If elems is not a copy of array, mode has no effect.
The value of mode has the following three situations:
- 0: copy content and release elems buffer
- JNI_COMMIT: copy content but do not release elems buffer
- JNI_ABORT: free buffer without copying possible changes
Most of the time, programmers pass "0" as an argument because this ensures consistent behavior of pinning and copying arrays. Other options give the programmer more control over memory.
Specific functions for specific primitive type array elements are described below:
- Replace Release <PrimitiveType> ArrayElements with one of the actual primitive> type functions below
- Replace ArrayType with the corresponding basic array type
- Replace NativeType with local variable
The details of freeing arrays of primitive types are described below. You should make the following substitutions:
Release<PrimitiveType>ArrayElements Routines Array Type Native Type
ReleaseBooleanArrayElements() jbooleanArray jboolean
ReleaseByteArrayElements() jbyteArray jbyte
ReleaseCharArrayElements() jcharArray jchar
ReleaseShortArrayElements() jshortArray jshort
ReleaseIntArrayElements() jintArray jint
ReleaseLongArrayElements() jlongArray jlong
ReleaseFloatArrayElements() jfloatArray jfloat
ReleaseDoubleArrayElements() jdoubleArray jdouble
Parameter explanation:
- env: JNI interface pointer
- array: Java array
- elems: pointer to an array of primitive types
- mode: release mode
(8), copy the array series of basic types in the past
void Get<PrimitiveType> ArrayRegion(JNIEnv *env,ArrayType array,jsize start,jsize len,NativeType *buf);
Copy an array of primitive types to buff
Specific functions for specific primitive type array elements are described below:
- Replace Get<PrimitiveType> ArrayRegion with one of the actual primitive> type functions below
- Replace ArrayType with the corresponding basic array type
- Replace NativeType with local variable
Get<PrimitiveType>ArrayRegion Routine Array Type Native Type
GetBooleanArrayRegion() jbooleanArray jboolean
GetByteArrayRegion() jbyteArray jbyte
GetCharArrayRegion() jcharArray jchar
GetShortArrayRegion() jshortArray jhort
GetIntArrayRegion() jintArray jint
GetLongArrayRegion() jlongArray jlong
GetFloatArrayRegion() jfloatArray jloat
GetDoubleArrayRegion() jdoubleArray jdouble
Parameter explanation:
- env: JNI interface pointer
- array: Java array
- start: start index
- len: the length to be copied
- buf: target buffer
abnormal:
- Throws ArrayIndexOutOfBoundsException if the index is invalid
(9), copy the array of the basic type array back to the series
void Set<PrimitiveType> ArrayRegion(JNIEnv *env,ArrayType array,jsize start,jsize len,const NativeType *buf);
It is mainly a function for buffering and copying arrays of basic types.
Specific functions for specific primitive type array elements are described below:
- Replace Set<PrimitiveType>ArrayRegion with one of the actual basic> type functions below
- Replace ArrayType with the corresponding basic array type
- Replace NativeType with local variable
Set<PrimitiveType>ArrayRegion Routine Array Type Native Type
SetBooleanArrayRegion() jbooleanArray jboolean
SetByteArrayRegion() jbyteArray jbyte
SetCharArrayRegion() jcharArray jchar
SetShortArrayRegion() jshortArray jshort
SetIntArrayRegion() jintArray jint
SetLongArrayRegion() jlongArray jlong
SetFloatArrayRegion() jfloatArray jfloat
SetDoubleArrayRegion() jdoubleArray jdouble
Parameter explanation:
- env: JNI interface pointer
- array: Java array
- start: start index
- len: the length to be copied
- buf:源buffer
abnormal:
- ArrayIndexOutOfBoundsException will be thrown if the index is invalid
(10), Supplement
Starting from JDK/JER 1.1, the Get/Release<primitivetype>ArrayElements function is provided to obtain pointers to primitive array elements. Returns a pointer to the original array if the VM supports locking, otherwise a copy.
Starting from JDK/JRE 1.3 new features are introduced, even if the VM does not support locking, native code can obtain direct pointers to array elements.
void *GetPrimitiveArrayCritical(JNIEnv *env,jarray array,jboolean *isCopy);
void ReleasePrimitiveArrayCritical(JNIEnv *env,jarray array,void *carray,jint mode);
Although these two functions are very similar to the Get/Release <primitivetype> ArrayElements function above, there are still many restrictions when using this function.
After calling GetPrimitiveArrayCritical and before calling ReleasePrimitiveArrayCritical, this area cannot call other JNI functions, nor can it call any system calls that may cause the thread to block and wait for another Java thread.
For example, the current thread cannot call the read function to read streams that are being written by other streams.
Nine system-level operations
(1) Registration method
jint RegisterNatives(JNIEnv *env,jclass clazz,const JNINativeMethod *methods,jint nMethod);
The local method is registered according to the clazz parameter, and the methods parameter formulates the JNINativeMethod structure array, which contains the name, signature and function pointer of the local method. Among them, the name and signature are pointers to the encoding "UTF-8"; the nMethod parameter indicates the number of local methods in the array.
Here is the JNINativeMethod structure:
typedef struct {
char *name;
char *signature;
void *fnPtr;
} JNINativeMethod;
Parameter explanation:
- env: JNI interface pointer
- clazz: Java class object
- methods: native methods in the class
- nMethod: the number of native methods in the class
return;
- Success returns 0, failure returns a negative number
abnormal:
- If the specified method is not found or the method is not a native method, NoSuchMethodError is thrown.
(2) Cancellation method
jint UnregisterNatives(JNIEnv *env,jclass clazz);
Unregister a native method. The class reclaims the state that has not been registered by the function before. This function generally cannot be called in Native code, and it provides a method for reloading and relinking native libraries for specific programs.
Parameter explanation:
- JNI: interface pointer
- clazz: Java class object
return:
- If the logout is successful, it returns 0, and if it fails, it returns a negative number
(3) Monitoring operation
jint MonitorEnter(JNIEnv *env,jobject obj);
The monitor associated with the underlying Java object referenced by obj. obj reference cannot be null. Every Java object has an associated monitor. If the current thread already has a monitor associated with obj, it will add the monitor's counter to indicate the number of times this thread has entered the monitor. If the monitor associated with obj does not belong to any thread, the current thread will become the owner of the monitor and set the counter to 1. If other counters already own the monitor, the current thread will wait until the monitor is acquired Release, and then take ownership of the monitor.
A monitor invoked through the MonitorEnter JNI function cannot be exited with the monitorexitJVM instruction or a synchronous method. The MonitorEnterJNI function call and the monitorenter Java virtual machine instruction may compete to enter the monitor with the same object.
To avoid deadlocks, monitors entered through the MonitorEnterJNI function call must be exited with the MonitorExitJNI call, unless the DetachCurrentThread interface is implicitly called to release the JNI monitor
Parameter explanation:
- env: JNI interface pointer
- obj: ordinary Java object or class object
return:
- Success returns 0, failure returns a negative number
(4) Monitor exit
jint MonitorExit(JNIEnv *env,jobject obj);
The current thread owns the monitor associated with this obj, and the thread decrements the counter to indicate the number of times the thread has entered the monitor. If the value of the counter becomes 0, the thread releases the monitor. Native code cannot directly call MonitorExit to release the monitor. Instead, use the Java Virtual Machine instruction to release the monitor through a synchronous method
Parameter explanation:
- env: JNI interface pointer
- obj: ordinary Java object or class object
return:
- Success returns 0, failure returns a negative number
abnormal:
- If the current thread does not own the monitor, an IllegalMonitorStateException should be thrown
Ten NIO operations
NIO-related operations allow Native code to directly access java.nio's direct buffers. The content of the direct buffer may exist in local memory outside of the normal garbage collector. For information on direct buffers, refer to the specifications of the NIO and java.nio.ByteBuffer classes.
In JDK/JRE 1.4 new JNI functions were introduced that allow inspection and manipulation of direct buffers
- NewDirectByteBuffer
- GetDirectBufferAddress
- GetDirectBufferCapacity
Every Java virtual machine implementation is required to support these features, but not every implementation is required to support JNI access to direct buffers. If the JVM does not support such access, the NewDirectByteBuffer and GetDirectBufferAddress functions must always return NULL, and the GetDirectBufferCapacity function must always return -1. If the JVM does support such access, then these three functions must be implemented to return suitable values.
(1) Return ByteBuffer
jobject NewDirectByteBuffer(JNIEnv *env,void *address,jlong capacity);
Allocates and returns a direct java.nio.ByteBuffer memory block capacity bytes starting at memory address address.
Native code that calls this function and returns a byte buffer object must ensure that the buffer points to a reliable memory area that can be read and written. Entering an illegal memory location may return an arbitrary value, DNA will not be visibly impressed, and an exception may be thrown.
Parameter explanation:
- env: JNIEnv interface pointer
- address: the starting address of the memory area
- capacity: the size of the memory area
return:
Returns a local reference to a newly opened java.nio.ByteBuffer object. Returns NULL if an exception occurs. If the JVM does not support JNI access to direct buffers, it will also return NULL
abnormal:
Returns OutOfMemoryError if buffer allocation fails
(2) Return the initial address of the object in the direct buffer
void* GetDirectBufferAddress(JNIEnv *env,jobject buf);
Get and return the initial memory address of java.nio.Buffer.
This function allows Native code to access the same memory area as Java code through a direct buffer object.
Parameter explanation:
- env: JNIEnv interface pointer
- buffer:java.nio.Buffer对象
return:
Returns the initial address of the memory region. Returns NULL if the memory region is undefined, returns NULL if the given object is not a java.nio.buffer, or returns NULL if the virtual machine does not support JNI access.
(3) Return the memory capacity of the object in the direct buffer
jlong GetDirectBufferCapacity(JNIEnv *env,jobject buf);
Get and return the memory capacity of java.nio.Buffer. The capacity is the number of elements that the memory area can hold
parameter:
- env: JNIEnv interface pointer
- buffer:java.nio.Buffer对象
return:
Returns the capacity of the memory region. Returns -1 if the specified object is not a java.nio.buffer, or if the object is an unaligned view buffer and the processor architecture does not support aligned access. Returns -1 if the virtual machine does not support JNI access.
11. Reflection support
If the programmer knows the names and types of methods and properties, he can directly use JNI to call Java methods or access Java fields. The Java core reflection API allows reflection of Java classes at runtime. JNI provides a set of conversion functions between field and method IDs used in JNI and field and method objects used in the Java Core Reflection API.
(1) Conversion and acquisition method ID
jmethodID FromReflectedMethod(JNIEnv *env,jobject method);
Convert a java.lang.reflect.Method or java.lang.reflect.Constructor object to a method ID.
Parameter explanation:
- env: JNIEnv interface pointer
- method: java.lang.reflect.Method or java.lang.reflect.Constructor object
return:
- Method ID
(2), conversion to obtain attribute ID
jfield FromReflectedField(JNIEnv *env,jobject field);
Convert java.lang.reflect.Field to ID.
Parameter explanation:
- env: JNIEnv interface pointer
- field: java.lang.reflect.Field object
return:
- Region ID
(3) Reverse transformation and obtain the method object
jobject ToReflectedMethod(JNIEnv *env,jclass clazz,jmethodID methodID, jboolean isStatic);
Convert method ID from cls to java.lang.reflect.Method or java.lang.reflect.Constructor object. isStatic must be set to JNI_TRUE if the method ID points to a static property, or JNI_FALSE otherwise.
Parameter explanation:
- env: JNIEnv interface pointer
- clazz: Java class object
- methodID: the method id corresponding to the Java class
- isStatic: whether it is a static method
return
Corresponds to the Java layer java.lang.reflect.Method or java.lang.reflect.Constructor object. Returns 0 on failure
abnormal:
If there is insufficient memory, an OutOfMemoryError is thrown.
(4), reverse transformation and get the attribute object
jobject ToReflectedField(JNIEnv *env,jclass cls,jfieldID field,jboolean isStatic)
Convert the attribute ID from cls to java.lang.reflect.Field object. isStatic must be set to JNI_TRUE if the property ID points to a static property, or JNI_FALSE otherwise.
Parameter explanation:
- env: JNIEnv interface pointer
- cls: Java class object
- methodID: Java corresponding attribute ID
- isStatic: whether it is a static property
return:
Return java.lang.reflect.Field object successfully, return 0 if failed
abnormal:
Throws OutOfMemoryError if out of memory
12. Obtain a virtual machine
jint GetJavaVM(JNIEnv *env,JavaVM **vm);
Returns the java virtual machine interface corresponding to the current thread. The returned result is saved in vm.
Parameter explanation:
- env: JNI interface pointer
- vm: save the virtual machine pointer
return:
It returns 0 on success, and a negative number on failure.