The JNI was introduced in the previous article. and Java invoke JNI. This article is about JNI calling Java methods.
By using the appropriate JNI functions, you can create Java objects, get, set static (static), and instance (instance) domains, and invoke static (static) and instance (instance) functions.
JNI identifies domains and methods by ID. The ID of a domain or method is a required number of functions that handle both the domain and the method.
The following table lists the JNI functions that are used to obtain static (static) and instance (instance) fields and methods. Each function accepts (as a parameter) the class of the field or method, their names, symbols, and their corresponding return Jfieldid or Jmethodid.
Function |
Descriptive narrative |
Getfieldid |
Gets the ID of the domain of an instance |
Getstaticfieldid |
Get the ID of a static domain |
Getmethodid |
The ID of the method that gets an instance |
Getstaticmethodid |
Get the ID of a static method |
Constructs an instance of a Java object
Jclass cls = (*env)->findclass (env, "lpackagename/classname;"); Create a reference to a class
Jmethodid id = (*env)->getmethodid (env, CLS, "", "(D) V"); Note that the name of the method here is "", which indicates that this is a constructor. And the construction parameters are double type.
Jobject obj = (*env)->newobjecta (env, CLS, id, args); To obtain an instance, args is the parameter of the constructor, which is a jvalue* type.
The first is to obtain a class reference for the Java Class (*ENV)->findclass (env, "lpackagename/classname;"); Please note the number of references:lpackagename/classname; . L represent this is a description of an object type, Packagename/classname is the object's ear class path, please note that you must end with a semicolon (;)!
The ID of the function is then obtained. Jmethodid id = env->getmethodid (CLS, "", "(D) V"); The first one is the class reference you just got, the second is the name of the method, and the last one is the signature of the method .
difficult to understand function signatures
The definition of Jninativemethod is as follows:
Jclass cls = (*env)->findclass (env, "lpackagename/classname;"); Create a reference to a class
Jmethodid id = (*env)->getmethodid (env, CLS, "", "(D) V"); Note that the name of the method here is "", which indicates that this is a constructor. And the construction parameters are double type.
Jobject obj = (*env)->newobjecta (env, CLS, id, args); Get an example. Args is the parameter of the constructor, which is a jvalue* type.
The first variable name is the name of the function in Java.
The second variable, signature, uses a string to describe the function's arguments and return values.
A third variable, fnptr, is a function pointer. Point to the C function.
It is difficult to understand the second number of parameters. Like what
"() V"
"(II) V"
"(ljava/lang/string; ljava/lang/string;) V "
These characters are actually corresponding to the function's parameter type one by one.
The characters in "()" indicate the number of references. The latter represents the return value. For example, "() V" means void Func ();
"(II) V" denotes void Func (int, int);
What about the rest of it? Please see the table below:
Type |
Symbol |
Boolean |
Z |
Byte |
B |
Char |
C |
Short |
S |
Int |
I |
Long |
L |
Float |
F |
Double |
D |
void |
V |
Object objects |
Lclassname; L class name; |
Arrays |
[Array-type [Array type] |
Methods method |
(argument-types) Return-type (parameter type) return type
|
Add a little bit:
1, the method parameter or the return value is the object in Java, the signature must be "L" plus its path, but this path must be separated by "/". These rules are also used by the objects that you define
Say java.lang.String for "java/lang/string", com.nedu.jni.helloword.Student for "lcom/nedu/jni/helloword/student;"
2. When the method parameter or the return value is an array type, precede the [
For example [I means int[],[[[d represents double[][][]. That is, a few-dimensional array adds several [
methods for invoking Java objects in local methods1. Get the class of the Java object you need to access:Jclass cls = (*env)->getobjectclass (env, obj); Use the Getobjectclass method to get the corresponding jclass for obj.
Jclass cls = (*env)->findclass ("Android/util/log")//Direct Search for class name, if static decorated class.
2. Get Methodid:Jmethodid mid = (*env)->getmethodid (env, CLS, "Callback", "(I) V");//getstaticmethodid (...). Get the ID of a static method use the Getmethdoid method to get the methdoid of the method you want to use
The meaning of its parameters:
env-->jnienv
cls--> The first step to get the Jclass
"Callback"-the method name to invoke
"(I) V"--signature of the method, signed with the preceding JNI rule.
3. Calling method: (*env)->callvoidmethod (env, obj, Mid, depth),//Callstaticintmethod (...), calling static method
Use the Callvoidmethod method to invoke the method. The meaning of the number of references:
Env-->jnienv
Obj--> through the local method jobject
Mid--> the Methodid to invoke (that is, the Methodid obtained in the second step)
The required number of depth--> methods (the corresponding method needs to be added to the corresponding number of parameters)
Note: The Callvoidmethod method call is used here, because there is no return value and the corresponding method is assumed if there is a return value. Will be mentioned in the following.
Callvoidmethod Callstaticvoidmethod
Callintmethod Callstaticvoidmethod
Callbooleanmethod Callstaticvoidmethod
Callbytemethod Callstaticvoidmethod
JNI manipulation of Java's string object
String objects passed from a Java program are corresponding to the jstring type in the local method, and the jstring type differs from the char* in C. So if you use it directly as a char*, it will go wrong.
Therefore, it is necessary to convert jstring to char* in C + +, using the method provided by JNIEnv.
const char *STR = (*env)->getstringutfchars (env, JSTR, 0);(*env)->releasestringutfchars (env, JSTR, str);
Here, the Getstringutfchars method is used to convert the incoming prompt (jstring type) into the UTF-8 format, which is used in the local method.
Note: After you have finished using the object you converted, you need to display the call Releasestringutfchars method. Lets the JVM release space for objects that are converted to UTF-8 string. Assume that the call is not displayed. The object is persisted in the JVM and is not reclaimed by the garbage collector, causing a memory overflow.
Here are some methods for JNI access to the string object:
- Getstringutfchars convert jstring into UTF-8 format char*
- Getstringchars convert jstring into Unicode format char*
- Releasestringutfchars releasing pointers to char* in UTF-8 format
- Releasestringchars releasing pointers to char* in Unicode format
- Newstringutf creating a String object in UTF-8 format
- NewString creating a Unicode-formatted string object
- Getstringutflength gets the length of the char* in UTF-8 format
- Getstringlength gets the length of the char* in Unicode format
The following methods provide two string objects and char* for mutual transfer:
/* C + + string turn to Java jstring */
Jstring chartojstring (jnienv* env, const char* PAT)
{
Jclass strclass = (*env)->findclass (env, "java/lang/string");
Jmethodid Ctorid = (*env)->getmethodid (env, strclass, "", "([bljava/lang/string;) V");
Jbytearray bytes = (*env)->newbytearray (env, strlen (PAT));
(*env)->setbytearrayregion (env, Bytes, 0, strlen (PAT), (jbyte*) PAT);
Jstring encoding = (*env)->newstringutf (env, "UTF-8");
Return (jstring) (*env)->newobject (env, strclass, Ctorid, Bytes, encoding);
}
/* Java jstring turn to C + + char* */
char* Jstringtochar (jnienv* env, jstring jstr)
{
char* pStr = NULL;
Jclass jstrobj = (*env)->findclass (env, "java/lang/string");
jstring encode = (*env)->newstringutf (env, "utf-8");
Jmethodid Methodid = (*env)->getmethodid (env, jstrobj, "GetBytes", "(ljava/lang/string;) [B");
Jbytearray ByteArray = (Jbytearray) (*env)->callobjectmethod (env, JSTR, Methodid, encode);
Jsize StrLen = (*env)->getarraylength (env, ByteArray);
Jbyte *jbuf = (*env)->getbytearrayelements (env, ByteArray, jni_false);
if (Jbuf > 0)
{
PSTR = (char*) malloc (StrLen + 1);
if (!PSTR)
{
return NULL;
}
memcpy (PStr, Jbuf, StrLen);
Pstr[strlen] = 0;
}
Env->releasebytearrayelements (ByteArray, jbuf, 0);
return pStr;
}
In fact, it is the same idea to call Java in the JNI and not quite the same in Java, for example, to find a class first. Then find the structure, and then create the object. Then a series of operations ... Wait a minute.
References: http://zhiweiofli.iteye.com/blog/1830321
If you have any questions, please leave a message, reproduced the source.
Java Native Interface JNI call Java method