JNI allows you to call Java class methods from the local code.
To do this, you must use the invocation API to create and initialize a JVM in your local code.
The following are typical cases where you may decide to call Java code from C/C ++ code:
1. The code to be implemented is platform-independent and will be used for functions across multiple platforms.
2. Access the code or code library written in Java in the local application.
3. You want to use the standard Java class library from your local code.
Four steps to call Java code from a C/C ++ program:
1. Write Java code.
This step contains writing one or more Java classes that implement (or call other methods) the functions you want to access.
2. Compile the Java code.
Before using these Java classes, you must successfully compile them into bytecode.
3. Write C/C ++ code.
This code will create and instantiate JVM and call the correct Java method.
4. Run the local C/C ++ application.
The application is running to check whether it works properly. We will also discuss some tips for handling common errors.
Step 1: Write Java code
Starting from writing one or more java source code files, these files will implement the functions that we want the local C/C ++ code to use.
The following shows a Java code example jni_ccalljava_test.java:
package test;public class JNI_cCalljava_test { public static int intMethod(int n) { return n*n; }public static boolean booleanMethod(boolean bool) { return !bool;}}
Note: jni_ccalljava_test.java implements two static Java Methods: intmethod (INTN) and booleanmethod (Boolean bool) (3rd rows and 7th rows respectively ). The static method is a class method that does not need to be associated with the object instance. It is easier to call static methods because you do not need to instantiate objects to call them.
Step 2: compile Java code
Next, we compile the Java code into bytecode.
One way to do this is to use the Java compiler javac provided with the SDK. The command used is:
Jni_ccalljava_test. Java
Or you can simply write and save it in external ose.
Step 3: Write C/C ++ code
All Java bytecode must be executed in JVM even if it is run in a local application.
Therefore, the C/C ++ application must contain the call used to create and initialize the JVM.
For convenience, the SDK contains JVM as a shared library file (JVM. dll or JVM. So). This library file can be embedded into local applications.
Let's start by looking at the entire code of the C and C ++ applications, and then compare them.
C applications with embedded JVM:
# Include <JNI. h> // JNI. h file contains all types and function definitions of JNI required in C code # ifdef _ Win32 # define path_separator ';' # else # define path_separator ':' # endif // 1. including preparing local applications to process Java code // 2. embed JVM into local applications // 3. then, find and call the Java method in the application. Int main () {/* Next, declare all variables to be used in the program. Javavmoption options [] has various options for JVM. When declaring a variable, make sure that the declared javavmoption options [] array is large enough to accommodate all the options you want to use. In this example, the only option we use is the class path option. In this example, all our files are in the same directory, so set the class path to the current directory. You can set a class path to point it to any directory structure you want to use. */Javavmoption options [1]; jnienv * env; JavaVM * JVM; javavminitargs vm_args;/* jnienv * env indicates the JNI execution environment. JavaVM JVM is a pointer to JVM. We mainly use this pointer to create, initialize, and destroy JVM. Javavminitargs vm_args indicates various JVM parameters that can be used to initialize JVM. */Long status; jclass CLS; jmethodid mid; jint Square; jboolean not;/* avavminitargs structure indicates the JVM initialization parameter. Before executing Java code, you can use these parameters to customize the runtime environment. As you can see, these options are one parameter, and the Java version is another parameter. Set these parameters as follows: * // * set the class path for JVM so that it can find the required Java class. In this specific example, because both sample2.class and sample2.exe are in the same directory, set the class path to the current directory. The code used to set the class path for sample2.c is as follows: */options [0]. optionstring = "-djava. class. path =. "; memset (& vm_args, 0, sizeof (vm_args); vm_args.version = jni_version_1_2; vm_args.noptions = 1; vm_args.options = options;/* after creating the JVM to process all the settings, now we are ready to create the JVM. If the call method succeeds, the method returns zero. Otherwise, jni_err is returned if the JVM cannot be created. */Status = jni_createjavavm (& JVM, (void **) & ENV, & vm_args); If (status! = Jni_err) {/* Find and load the Java class. Once the JVM is created, you can prepare to start running Java code in the Local application. First, you need to use the findclass () function to find and load the Java class, as shown in the following: CLS variable storage results after the findclass () function is executed. If this class is found, the CLs variable indicates the Java class handle. If the class cannot be found, the CLS will be zero. */CLS = (* env)-> findclass (ENV, "test/jni_ccalljava_test"); printf ("test1, CLS = % d... \ n ", CLS); If (CLS! = 0) {/* Find the Java method. Next, we want to use the getstaticmethodid () function to find a method in this class. We want to find the method intmethod, which receives an int parameter and returns an int. The following code finds intmethod: */Mid = (* env)-> getstaticmethodid (ENV, CLS, "intmethod", "(I) I "); /* the mid variable stores the result after the getstaticmethodid () function is executed. If this method is found, the mid variable indicates the handle of this method. If this method cannot be found, the mid value is zero. */If (Mid! = 0) {/* The callstaticintmethod () method accepts Cls (representing classes), mid (representing methods), and one or more parameters for this method. In this example, the parameter is int 5. */Square = (* env)-> callstaticintmethod (ENV, CLS, mid, 5); printf ("result of intmethod: % d \ n", square );} mid = (* env)-> getstaticmethodid (ENV, CLS, "booleanmethod", "(z) z"); If (Mid! = 0) {not = (* env)-> callstaticbooleanmethod (ENV, CLS, mid, 1); printf ("result of booleanmethod: % d \ n ", not) ;}} (* JVM)-> destroyjavavm (JVM); Return 0;} elsereturn-1 ;}
C ++ applications with embedded JVM
#include <jni.h>#ifdef _WIN32#define PATH_SEPARATOR ';'#else#define PATH_SEPARATOR ':'#endifint main(){JavaVMOption options[1];JNIEnv *env;JavaVM *jvm;JavaVMInitArgs vm_args;long status;jclass cls;jmethodID mid;jint square;jboolean not;options[0].optionString = "-Djava.class.path=.";memset(&vm_args, 0, sizeof(vm_args));vm_args.version = JNI_VERSION_1_2;vm_args.nOptions = 1;vm_args.options = options;status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);if (status != JNI_ERR){cls = env->FindClass("Sample2");if(cls !=0){ mid = env->GetStaticMethodID(cls, "intMethod", "(I)I");if(mid !=0){ square = env->CallStaticIntMethod(cls, mid, 5);printf("Result of intMethod: %d\n", square);}mid = env->GetStaticMethodID(cls, "booleanMethod", "(Z)Z")if(mid !=0){ not = env->CallStaticBooleanMethod(cls, mid, 1);printf("Result of booleanMethod: %d\n", not);}}jvm->DestroyJavaVM();return 0;}elsereturn -1;}
Comparison of C and C ++ implementations
C and C ++ code are almost the same. The only difference is the method used to access the JNI function.
In C, to retrieve the value referenced by the function pointer, A (* env)-> prefix must be added before JNI function is called.
In C ++, The jnienv class has inline member functions that process function pointer lookup.
Therefore, although the two lines of code access the same function, each language has its own syntax, as shown below.
C Syntax:
CLS = (* env)-> findclass (ENV, "sample2 ");
C ++ Syntax:
CLS = env-> findclass ("sample2 ");
C Syntax:
Mid = (* env)-> getstaticmethodid (ENV, CLS, "intmethod", "(I) I ");
C ++ Syntax:
Mid = env-> getstaticmethodid (CLS, "intmethod", "(I) I ");
C Syntax:
Square = env-> callstaticintmethod (CLS, mid, 5 );
C ++ Syntax:
Square = (* env)-> callstaticintmethod (ENV, CLS, mid, 5 );
C Syntax:
(* JVM)-> destroyjavavm (JVM );
C ++ Syntax:
JVM-> destroyjavavm ();
Step 4: run the application
Run the C application and make sure the code works properly. When you run sample2.exe, you can get the following results:
Windows:
Use vc6.0 to create a common C Language Project
The header file path settings are the same as those in the C language for Java calls.
JVM. Lib is required for connection
Right-click the created Project and click Settings. The link option bar adds the database path.
C: "\ Program Files" \ Java \ jdk1.6.0 _ 10 \ Lib \ JVM. Lib
Add the preceding statements to project options and separate them with spaces. The programe files are enclosed by double quotation marks.
The JVM. dll dynamic library is required for running, and the following path must be added to the system environment variable:
C: \ Program Files \ Java \ jdk1.6.0 _ 10 \ JRE \ bin \ Server
Method: Right-click my computer-> properties-> advanced-> environment variables-> path editing, and add the preceding Paths Based on the original environment variables. Note that the paths are separated ";".
Place the Java code generated by the external ose inJni_ccalljava_test.exe is in the same directory (copy the registration folder as needed)
E: \ sample2>Jni_ccalljava_test. Exe
Result of intmethod: 25
Result of booleanmethod: 0