JNI/NDK Development Guide (8) -- call constructor and parent class instance method, jnindk
Reprinted please indicate the source: http://blog.csdn.net/xyang81/article/details/44002089
In Chapter 6th, we learned how to call Java static methods and instance methods at the Native layer. The sample code that calls an instance method also mentions calling constructors to implement an object, however, I did not provide a detailed description. If you have not read this document, go to JNI/NDK Development Guide (6) -- C/C ++ to access Java instance methods and static methods. This chapter describes in detail the two initial methods of an object and how to call the method of the parent class instance rewritten by the subclass object.
Let's first go back to the process of instantiating an object in Java and calling the method of the parent class instance. First look at a piece of code:
Package com. study. jnilearn; public class Animal {public void run () {System. out. println ("Animal. run... ") ;}} package com. study. jnilearn; public class Cat extends Animal {@ Override public void run () {System. out. println (name + "Cat. run... ") ;}} public static void main (String [] args) {Animal cat = new Cat (" Tom "); cat. run ();}
As you can see, the above code is very simple. There are two classes: Animal and Cat. The Animal class defines the run and getName methods. Cat inherits from Animal, and overwrites the run method of the parent class. In the main method, a cat variable of the Animal type is defined first, pointing to the Instance Object of the Cat class, and then calling its run method.When executing the new Cat ("Tom") Code, the Cat class will first be allocated memory space (the size of the allocated memory space is determined by the number of Cat class member variables ), then, call Cat's parameter-based constructor to initialize the object.Cat is of the Animal type, but it points to the reference of the Cat instance object, and Cat overwrites the run method of the parent class, because the run method has polymorphism when it is called, therefore, the Cat run instead of the Animal run is accessed. The output is as follows:Tom Cat. run...
To call the run method of the parent class, you only need to call super. run () in the run method of Cat, which is quite simple.
Students who have written C or C ++ should have a profound concept of memory management,Stack space and stack spaceThe memory size of the stack space is limited by the operating system, which is automatically managed by the operating system and is fast. Therefore, the local variables and function-shaped parameters defined in the function are stored in the stack space. The operating system does not limit the memory size of heap space. It is only subject to the limitation of physical memory. The memory needs to be managed by programmers themselves. The memory dynamically allocated by using the malloc keyword in C language and the memory allocated by the new object created in C ++ are stored in the heap space, use free or delete/delete [] to release the memory after use.Here, we will not discuss much about C/C ++ memory management knowledge. If you are interested, please use Baidu.We all know that writing Java programs does not require manual memory management, memory Management all the annoying things are managed by a thread called GC (when an object is not referenced by other objects, the object will be released by GC ). However, I think the internal memory management principle of Java is very similar to that of C/C ++. In the above example, Animal cat = new Cat ("Tom "); the local variable cat is stored in the stack space, new Cat ("Tom"); The created instance object is stored in the heap space, and a reference to the memory address is returned, which is stored in the cat variable. In this way, you can access all visible members of the cat instance through the reference pointed to by the Cat variable.
Therefore, you can create an object in two steps:
1. allocate memory space for objects
2. initialize the object (call the object construction method)
The following example shows how to call the object constructor and parent class instance methods in JNI. In order to let the example clearly reflect the calling process of the constructor and the parent class instance method, Animal and Cat classes are defined. Animal defines the constructor of a String parameter, one member variable name, two member functions run and getName. Cat inherits from Animal and overwrites the run method. Create a Cat object instance in JNI and call the run and getName methods of the Animal class. The Code is as follows:
// Animal.javapackage com.study.jnilearn;public class Animal { protected String name; public Animal(String name) { this.name = name; System.out.println("Animal Construct call..."); } public String getName() { System.out.println("Animal.getName Call..."); return this.name; } public void run() { System.out.println("Animal.run..."); } }// Cat.javapackage com.study.jnilearn;public class Cat extends Animal { public Cat(String name) { super(name); System.out.println("Cat Construct call...."); } @Override public String getName() { return "My name is " + this.name; } @Override public void run() { System.out.println(name + " Cat.run..."); }}// AccessSuperMethod.javapackage com.study.jnilearn;public class AccessSuperMethod { public native static void callSuperInstanceMethod(); public static void main(String[] args) { callSuperInstanceMethod(); } static { System.loadLibrary("AccessSuperMethod"); }}
The AccessSuperMethod class is the program entry, which defines a native method callSuperInstanceMethod. The jni function prototype generated by javah is as follows:
/* Header for class com_study_jnilearn_AccessSuperMethod */#ifndef _Included_com_study_jnilearn_AccessSuperMethod#define _Included_com_study_jnilearn_AccessSuperMethod#ifdef __cplusplusextern "C" {#endif/* * Class: com_study_jnilearn_AccessSuperMethod * Method: callSuperInstanceMethod * Signature: ()V */JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessSuperMethod_callSuperInstanceMethod (JNIEnv *, jclass);#ifdef __cplusplus}#endif#endif
Implement the Java_com_study_jnilearn_AccessSuperMethod_callSuperInstanceMethod function, as shown below:
// AccessSuperMethod. c # include "example" JNIEXPORT void JNICALL example (using * env, jclass cls) {jclass cls_cat; jclass cls_animal; jmethodID example; using mid_run; using mid_getName; jstring c_str_name; jobject example; const char * name = NULL; // 1. Obtain the Cat class reference cls_cat = (* env)-> FindClass (env, "com/study/jnilearn/Cat "); if (cls_cat = NULL) {return;} // 2. Obtain the Cat constructor ID (the constructor name is <init>) mid_cat_init = (* env) -> GetMethodID (env, cls_cat, "<init>", "(Ljava/lang/String;) V"); if (mid_cat_init = NULL) {return; // only one constructor with the String parameter is not found} // 3. Create a String object as the constructor parameter c_str_name = (* env)-> NewStringUTF (env, "Tom"); if (c_str_name = NULL) {return; // failed to create the string (insufficient memory )} // 4. Create an instance of the Cat object (call the object construction method and initialize the object) obj_cat = (* env)-> NewObject (env, cls_cat, mid_cat_init, c_str_name ); if (obj_cat = NULL) {return;} // -------------- 5. Call the run and getName methods of the Cat parent class Animal -------------- cls_animal = (* env)-> FindClass (env, "com/study/jnilearn/Animal"); if (cls_animal = NULL) {return;} // Example 1: Call the parent class's run method mid_run = (* env) -> GetMethodID (env, cls_animal, "run", "() V"); // obtain the id if (mid_run = NULL) of the run method in the parent class Animal) {return;} // Note: obj_cat is the Cat instance, cls_animal is the Class reference of Animal, and mid_run is the method ID (* env) in Animal Class-> CallNonvirtualVoidMethod (env, obj_cat, cls_animal, mid_run); // Example 2: Call the getName method of the parent class // obtain the id of the getName method in the parent class Animal mid_getName = (* env)-> GetMethodID (env, cls_animal, "getName", "() Ljava/lang/String;"); if (mid_getName = NULL) {return;} c_str_name = (* env) -> CallNonvirtualObjectMethod (env, obj_cat, cls_animal, mid_getName); name = (* env)-> GetStringUTFChars (env, c_str_name, NULL); printf ("In C: animal Name is % s \ n ", name); // release the memory allocated by the string obtained from the java layer (* env)-> ReleaseStringUTFChars (env, c_str_name, name); quit: // delete a local reference (The subclass of jobject or jobject belongs to the referenced variable), allowing the VM to release resources referenced by the local variable (* env) -> DeleteLocalRef (env, cls_cat); (* env)-> DeleteLocalRef (env, cls_animal); (* env)-> DeleteLocalRef (env, c_str_name); (* env) -> DeleteLocalRef (env, obj_cat );}
Running result:
Code Description-call Constructor
The call constructor method is similar to the instance method of the call object. "<init>" is passed as the constructor ID of the Method Name Lookup class, then call the JNI function NewObject to call the object's constructor initialization object. The following code is used:
obj_cat = (*env)->NewObject(env,cls_cat,mid_cat_init,c_str_name);
The above code calls the JNI function NewObject to create an instance object referenced by Class. This function does two things: 1. Create an uninitialized object and allocate memory space; 2. Call the object's constructor to initialize the object. The two steps can also be performed separately to allocate memory for the object and then initialize the object, as shown in the following code:
// 1. Create an uninitialized object and allocate the memory obj_cat = (* env)-> AllocObject (env, cls_cat); if (obj_cat) {// 2. Call the object's constructor initialization object (* env)-> CallNonvirtualVoidMethod (env, obj_cat, cls_cat, mid_cat_init, c_str_name); if (* env) -> ExceptionCheck (env) {// check for abnormal goto quit ;}}
The AllocObject function creates an uninitialized object. before using this object, you must call CallNonvirtualVoidMethod to call the object's constructor to initialize the object. In addition, you must be very careful when using it to ensure that the constructor can be called at most once on an object. Sometimes it is useful to create an initialization object and then call the constructor at the right time. Nevertheless, in most cases, NewObject should be used to avoid the error-prone AllocObject/CallNonvirtualVoidMethod function.
Code Description-call the parent instance method
If a method is defined in the parent class and overwritten in the subclass, you can also call this instance method in the parent class. JNI provides a series of CallNonvirtualXXXMethod functions to support calling various return value type instance methods. To call an instance method defined in the parent class, follow these steps:
1. Use the GetMethodID function to obtain the method ID from a Class reference pointing to the parent Class.
Cls_animal = (* env)-> FindClass (env, "com/study/jnilearn/Animal"); if (cls_animal = NULL) {return;} // Example 1: call the run method of the parent class mid_run = (* env)-> GetMethodID (env, cls_animal, "run", "() V "); // obtain the idif (mid_run = NULL) {return;} of the run method in the parent class Animal ;}
2. Input subclass object, parent Class reference, parent Class method ID and parameters, and call CallNonvirtualVoidMethod,
CallNonvirtualBooleanMethod, CallNonvirtualIntMethod, and other functions. CallNonvirtualVoidMethod can also be used to call the constructor of the parent class.
// Note: obj_cat is the Cat instance, cls_animal is the Class reference of Animal, and mid_run is the method ID (* env)-> callvirtualnonvoidmethod (env, obj_cat, cls_animal, mid_run );
In fact, during development, this method of calling the parent class instance is rarely encountered. Generally, in JAVA, it is easy to: super. func (); but some special requirements may also be used, so it is necessary to know that this is the case.
Sample Code: https://code.csdn.net/xyang81/jnilearn