Reprint Please specify Source: http://blog.csdn.net/xyang81/article/details/42582213
Learning from the previous 5 chapters, we learned how to access the basic data types, strings, and arrays in the JVM through the JNI function. Next, let's learn how native code interacts with the properties and methods of any object in the JVM. For example, local code calls a method or property of an object in the Java layer, which is usually what we call a callback (callback) from a C + + layer native function. This knowledge point is divided into 2 articles respectively, this article first introduces the method callback, in the seventh chapter describes the local code access to Java properties.
Before you do that, it's helpful to review the implementation principle in the JVM when invoking a method in Java, to help explain the mechanism by which native code calls Java method implementations. Children's shoes written in Java know that calling a static method of a class directly through the class name. Method can be called. This is too simple, what good to say ... But in this call, the JVM is doing a lot of work for us. When we run a Java program, the JVM will first load all the relevant class files into the JVM using the program's runtime and load them on demand, meaning that a class will only be loaded when it is used. The purpose of this design is also to improve the performance of the program and save memory. So before we call a static method with the class name, the JVM first determines whether the class is loaded, and if it is not loaded into the JVM by ClassLoader , the JVM will look for the class from the Classpath path and, if found, will load it into the JVM. Then it is the static method that calls the class. If not found, the JVM throws a Java.lang.ClassNotFoundException exception that indicates that the class could not be found. ClassLoader is a mechanism for the JVM to load a class bytecode file, and for children who are not familiar with it, please read the article "in-depth analysis of Java ClassLoader principles". In fact, in the JNI development, the local code is also to follow the above process to access the class static method or instance method, following an example, in detail the local code calls the Java method process each step of the cluster:
Package com.study.jnilearn;/** * Accessmethod.java * Local code Access class instance method and static method * @author Yangxin */public class Accessmethod {Publ IC static native void Calljavastaticmethod (); public static native void Calljavainstacemethod ();p ublic static void Main (string[] args) {Calljavastaticmethod (); Calljavainstacemethod ();} static {system.loadlibrary ("Accessmethod");}}
Package com.study.jnilearn;/** * Classmethod.java * for local code calls * @author Yangxin */public class Classmethod {private static void Callstaticmethod (String str, int i) {System.out.format ("Classmethod::callstaticmethod called!-->str=%s," + "i= %d\n ", str, i);} private void Callinstancemethod (String str, int i) {System.out.format ("Classmethod::callinstancemethod called!--> str=%s, "+" i=%d\n ", str, i);}}
header files generated by Accessmethod.class:
/* Don't EDIT this file-it are machine generated */#include <jni.h>/* Header for class Com_study_jnilearn_accessme Thod */#ifndef _included_com_study_jnilearn_accessmethod#define _included_com_study_jnilearn_accessmethod#ifdef __ Cplusplusextern "C" {#endif */* Class: com_study_jnilearn_accessmethod * Method: Calljavastaticmethod * Signature: () V */jniexport void Jnicall java_com_study_jnilearn_accessmethod_calljavastaticmethod (JNIENV *, Jclass);/* Class: com_study_jnilearn_accessmethod * Method: Calljavainstacemethod * Signature: () V */ jniexport void Jnicall Java_com_study_jnilearn_accessmethod_calljavainstacemethod (jnienv *, jclass); #ifdef __ Cplusplus} #endif #endif
the implementation of the function prototype in the local code header file:
Accessmethod.c#include "Com_study_jnilearn_accessmethod.h"/* * Class:com_study_jnilearn_accessmethod * Method: Calljavastaticmethod * Signature: () V */jniexport void Jnicall java_com_study_jnilearn_accessmethod_ Calljavastaticmethod (jnienv *env, Jclass cls) {Jclass clazz = NULL; jstring str_arg = NULL; Jmethodid Mid_static_method; 1. Search Classmethod This class from Classpath path, and return class object clazz = (*env)->findclass (env, "Com/study/jnilearn/classmethod") ); if (clazz = = NULL) {return; }//2, find the Callstaticmethod method from the Clazz class Mid_static_method = (*env)->getstaticmethodid (Env,clazz, "Callstaticmethod "," (ljava/lang/string;i) V "); if (Mid_static_method = = NULL) {printf ("Callstaticmethod This static method cannot be found. "); Return }//3, call the Callstaticmethod static method of the Clazz class Str_arg = (*env)->newstringutf (env, "I am a static method"); (*env)->callstaticvoidmethod (Env,clazz,mid_static_method, Str_arg, 100); Delete local references (*env)->deletelocalref (Env,clazz); (*env)->deletelocalref (Env,str_arg);} /* * Class:com_study_jnilearn_accessmethod * Method:calljavainstacemethod * Signature: () V */jniexport void JNICA LL Java_com_study_jnilearn_accessmethod_calljavainstacemethod (jnienv *env, Jclass cls) {Jclass clazz = NULL; Jobject jobj = NULL; Jmethodid mid_construct = NULL; Jmethodid mid_instance = NULL; jstring str_arg = NULL; 1. Search Classmethod This class from Classpath path, and return class object clazz = (*env)->findclass (env, "Com/study/jnilearn/classmethod") ); if (clazz = = NULL) {printf ("Cannot find ' Com.study.jnilearn.ClassMethod ' this class"); Return }//2, gets the default constructor method ID of the class mid_construct = (*env)->getmethodid (Env,clazz, "<init>", "() V"); if (mid_construct = = NULL) {printf ("default constructor method not found"); Return }//3, find the ID of the instance method Mid_instance = (*env)->getmethodid (env, Clazz, "Callinstancemethod", "(ljava/lang/string;i) V "); if (mid_instance = = NULL) {return; }//4, creatingAn instance of this class Jobj = (*env)->newobject (env,clazz,mid_construct); if (jobj = = NULL) {printf ("Callinstancemethod method not found in Com.study.jnilearn.ClassMethod class"); Return }//5, call the object's instance method Str_arg = (*env)->newstringutf (env, "I am the instance method"); (*env)->callvoidmethod (env,jobj,mid_instance,str_arg,200); Delete local references (*env)->deletelocalref (Env,clazz); (*env)->deletelocalref (env,jobj); (*env)->deletelocalref (Env,str_arg);}
Operation Result:
Code parsing:
Accessmethod.java is the entry for the program, and in the main method, it calls the Calljavastaticmethod and Calljavainstacemethod These two native methods for testing native layer calls in Methodclass.java Callstaticmethod static and Callinstancemethod instance methods, the return values of both methods are void, with two arguments, string and int, respectively
First, Calljavastaticmethod static method implementation description
Jniexport void Jnicall Java_com_study_jnilearn_accessmethod_calljavastaticmethod (jnienv *env, Jclass CLS)
Navigate to Line 31 of ACCESSMETHOD.C:
(*env)->callstaticvoidmethod (Env,clazz,mid_static_method, Str_arg, 100);
The Callstaticvoidmethod function is prototyped as follows:
void (Jnicall *callstaticvoidmethod) (jnienv *env, Jclass cls, Jmethodid methodid, ...);
the function receives 4 parameters:
Env:jni function Table pointer
CLS: Call the static method's class object
Methodid: Method ID (because there are multiple methods in a class, a unique identity is required to determine which method in the calling Class)
Parameter 4: Method argument list
Complete the callback for the Java static method in the following four steps, as prompted by the function parameters:
The first step: call the Findclass function, pass in a class descriptor, the JVM will search for the class from the Classpath path, and return the Jclass type (a reference to store the class object). Note that the class descriptor for Classmethod is Com/study/jnilearn/classmethod, to be . (point) Replace all /(backslash)
(*env)->findclass (env, "Com/study/jnilearn/classmethod");
Step Two: call the Getstaticmethodid function, get the Callstaticmethod method ID from the Classmethod class, and return the Jmethodid type (a reference for storing the method). Argument Clazz is the first step to find the Jclass object, the argument "Callstaticmethod" is the method name, the argument "(Ljava/lang/string;i) V" is the signature of the method
(*env)->getstaticmethodid (Env,clazz, "Callstaticmethod", "(ljava/lang/string;i) V");
Step Three: call the Callstaticvoidmethod function and execute the Classmethod.callstaticmethod method call. Str_arg and 100 are arguments to the Callstaticmethod method.
Str_arg = (*env)->newstringutf (env, "I am static method");(*env)->callstaticvoidmethod (Env,clazz,mid_static_method, Str_ ARG, 100);
Note: The JVM defines the relevant functions for the return values of all data types. The return type of the Callstaticmethod method above is void, so call Callstaticvoidmethod. Depending on the return value type, JNI provides a series of functions with different return values, such as: Callstaticintmethod, Callstaticfloatmethod, Callstaticshortmethod, Callstaticobjectmethod, such as the invocation of a function with a return value of int, float, short, type Object, and a reference type that calls the Callstaticobjectmethod function uniformly. In addition, each function that returns a value type provides implementations that receive 3 types of arguments: callstaticXXXMethod (env, Clazz, Methodid, ...), CALLSTATICXXXMETHODV (env, Clazz, Methodid, va_list args), Callstaticxxxmethoda (env, Clazz, Methodid, const jvalue *args), respectively: Receive variable parameter list, receive Va_ The list acts as an argument and receives the const jvalue* as an argument. The following is a functional prototype of the three arguments callstaticvoidmethod in the jni.h header file:
void (Jnicall *callstaticvoidmethod) (jnienv *env, Jclass cls, Jmethodid methodid, ...); void (Jnicall *CALLSTATICVOIDMETHODV) (jnienv *env, Jclass cls, Jmethodid Methodid, va_list args); void (Jnicall *callstaticvoidmethoda) (jnienv *env, Jclass cls, Jmethodid methodid, const jvalue * args);
Fourth Step , releasing local variables
Delete local references (*env)->deletelocalref (env,clazz);(*env)->deletelocalref (ENV,STR_ARG);
Although the function ends, the JVM automatically frees up the memory space occupied by all local reference variables. However, it is more secure to manually release it because a reference table is maintained in the JVM to store local and global reference variables, and the maximum storage space for the table is tested to be 512 references, which can cause a reference table overflow if exceeded, and the JVM crashes. So it is a good habit to have the application on time release!
(local and global references are described in more detail in a later article)
Second, callinstancemethod example method implementation description
Jniexport void Jnicall Java_com_study_jnilearn_accessmethod_calljavainstacemethod (jnienv *env, Jclass CLS)
Navigate to line 43 of ACCESSMETHOD.C:
(*env)->callvoidmethod (env,jobj,mid_instance,str_arg,200);
The Callvoidmethod function is prototyped as follows:
void (Jnicall *callvoidmethod) (jnienv *env, Jobject obj, Jmethodid methodid, ...);
The function receives 4 parameters:
Env:jni function Table pointer
OBJ: Invoking an instance of this method
Methodid: Method ID
Parameter 4: The argument list of the method
complete the callback for the Java static method in the following six steps, as prompted by the function parameters:
The
first step, the same as the static method, first obtains the class object by the Findclass function
The second step is to get the constructor ID of the class, because the object that created the class first calls the class's constructor method. Here is an example of the default construction method
(*env)->getmethodid (Env,clazz, "<init>", "() V");
<init> represents the constructor method name for the class, () v for the constructor that has no return value (that is, the default constructor method)
step three, call Getmethodid to get Callinstancemethod's method ID
(*env)->getmethodid (env, Clazz, "Callinstancemethod", "(ljava/lang/string;i) V");
Fourth Step, call the NewObject function to create an instance object of the class
(*env)->newobject (env,clazz,mid_construct);
Fifth Step, call the Callvoidmethod function, execute the Classmethod.callinstancemethod method call, Str_arg and 200 are method arguments
Str_arg = (*env)->newstringutf (env, "I am the instance method");(*env)->callvoidmethod (env,jobj,mid_instance,str_arg,200);
as with JNI calls to Java static methods, the JVM defines the relevant functions (Callxxxmethod) for the return values of all data types, such as: Callintmethod, Callfloatmethod, Callobjectmethod, etc. , it also provides a function implementation that supports three types of arguments, taking Callvoidmethod as an example, the following is the prototype of the function in the jni.h header file:
void (Jnicall *callvoidmethod) (jnienv *env, Jobject obj, Jmethodid methodid, ...); void (Jnicall *CALLVOIDMETHODV) (jnienv *env, Jobject obj, Jmethodid methodid, va_list args); void (Jnicall *callvoidmethod A) (jnienv *env, Jobject obj, Jmethodid methodid, const jvalue * args);
Sixth Step, remove the local reference (removed from the reference table)
Delete local references (*env)->deletelocalref (env,clazz);(*env)->deletelocalref (env,jobj);(*env)->deletelocalref (env , Str_arg);
Iii. Signature of the method
In the above example, either a static method or an instance method must be passed in a jmethodid parameter. Because there are method overloads in Java (the same method name, the parameter list is different), it is clear to tell the JVM which method is called in the class or instance. When you call JNI's Getmethodid function to get a jmethodid, you need to pass in a method name and method signature, which is the method name defined in Java and the format of the method signature is:(parameter type list) return value . Parameter list, the reference type starts with L, followed by the full path name of the class (you need to replace. All with/), ending with a semicolon. Here are some examples:
The mapping between the Java base type and the parameter type and return value type in the method signature is as follows:
For example, the String fun (int A, float B, Boolean C, String D) corresponds to the Jni method signature: "(ifzljava/lang/string;) ljava/lang/string;"
Summarize:
1. Call the static method using the CALLSTATICXXXMETHOD/V/A function, XXX represents the data type of the return value. such as: Callstaticintmethod
2, call the instance method using the CALLXXXMETHOD/V/A function, XXX represents the returned data type, such as: Callintmethod
3. Get the ID of an instance method, use the Getmethodid function, pass in the method name and method signature
4, obtained with the ID of a static method, using the Getstaticmethodid function, passing in the method name and method signature
5. Get the constructor method ID, using the "<init>" method name
6. Get a class instance of the classes, and use the Findclass function to pass in the class descriptor. The JVM will start searching from the Classpath directory.
7. Create an instance of a class, use the NewObject function, pass in class reference and construct method ID
8. Delete the local variable reference, use Deletelocalref, pass in the reference variable
9. Method signature Format: (parameter list) returns a value type. Note: There is no need to separate the parameter list with spaces or other characters
10, Class Descriptor format: L Package name Path/class name, and package name between/separated. such as: ljava/lang/string;
11. Call Getmethodid to get the method ID and call Findclass to get the class instance, make the exception judgment
JNI/NDK Development Guide (vi)--c/c++ Access to Java instance methods and static methods