In the android framework, a media or bridge is required to organically associate the Java layer (upper layer) with C/C ++ (bottom layer) so that they can coordinate with each other, complete some tasks together. The Java Local interface (JNI, Java Native Interface) acts as a bridge between the two layers ), it allows Java code to interact with applications and libraries written based on C/C ++.
JNI provides a series of interfaces that allow Java classes and other programming languages such as C/C ++ (in JNI, these languages are called local languages) write Applications, modules, libraries for interactive operations. For example, JNI is required to use a specific function in the C language library in a Java class or a Java class library in the C language.
JNI is usually used in the following scenarios
- Focus on processing speed: If you have high requirements on the execution speed of a program, we recommend that you use C/C ++ to write code, then, on the Java layer, call part of the code written based on C/C ++ through JNI.
- Hardware control: in order to better control the hardware, the hardware control code is usually written in C language. With JNI, it is connected to the Java layer to implement hardware control.
- Reuse of C/C ++ code: During programming, C/C ++ code that has already been compiled is often used, which improves programming efficiency, it also ensures the security and robustness of the program. When reusing these C/C ++ code, it must be implemented through JNI.
To call the C function through JNI in Java code, follow these steps:
- Step 1: Write Java code
- Step 2: compile Java code (javac Java file)
- Step 3: generate the C code header file (javah Java class name, automatically generated)
- Step 4: compile C code (implement functions in the header file of C code)
- Step 5: generate a C Shared Library (use the tool to compile and generate a C Shared Library. The DLL file is under win, and the so file is under Linux)
- Step 6: run the Java program (Java class name)
Step 1: WriteJavaCode
First, compile the Java source code hellojni. Java that calls the C language.
public class HelloJNI { native void printHello(); 1 native void printString(String str); static{ System.loadLibrary("hellojni"); 2 } public static void main(String[] args) { // TODO Auto-generated method stub HelloJNI myJNI = new HelloJNI(); myJNI.printHello(); myJNI.printString("Hello world form printString function!"); }}
Note:
1. Use the "native" keyword in the Java class to declare the local method. This method corresponds to the JNI local function written in C/C ++ ." The native keyword informs the Java compiler that the method containing this keyword in Java code is only a declaration, which is written and implemented in other languages such as C/C ++.
2. After the local method is declared in the Java class, call system.Loadlibrary ()Method to load the C Runtime Library that implements the local method (static block is usually used to load the local Runtime Library in Java )). System.Loadlibrary ()Method to load the local library specified by the string parameter. The C Runtime library loaded varies with the operating system platform. In the window, call system.Loadlibrary ("hellojni "), Hellojni. dll will be loaded. in Linux, The libhellojni. So file will be loaded.
Step 2: CompileJavaCode
Use the following command to compile the Java source code:
Javac hellojni. Java
After hellojni. Java is compiled, the hellojni. Class file is generated. If you run the Java program directly at this time, an exception is thrown.
Unable to find the C Runtime library to be loaded by Java virtual machine because the hellojni. dll library file has not been created and loaded into Java code.
Next, create the hellojni. dll library file.
Step 3: generateCCode header file
To create a ing c function of a local method, you must prototype the function, which is stored in the C/C ++ header file. Java provides the javah tool, which is located under the bin directory of the installation directory of Java JDK and is used to generate the C/C ++ header file containing the function prototype. The usage is as follows:
Javah <Java class name that contains methods declared with native keywords>
Run the javah command to generate a C Language header file with the same name as the Java class name (that is, the javah command parameter) in the current directory. The generated C header file defines the C function prototype linked to the Java local method.
The generated hellojni. h file is as follows:
/* DO NOT EDIT THIS FILE - it is machine generated */ 1#include <jni.h>/* Header for class HelloJNI */ #ifndef _Included_HelloJNI#define _Included_HelloJNI#ifdef __cplusplusextern "C" {#endif/* * Class: HelloJNI * Method: printHello * Signature: ()V */JNIEXPORT void JNICALL Java_HelloJNI_printHello (JNIEnv *, jobject); /* * Class: HelloJNI 2 * Method: printString * Signature: (Ljava/lang/String;)V */JNIEXPORT void JNICALL Java_HelloJNI_printString (JNIEnv *, jobject, jstring); #ifdef __cplusplus}#endif#endif
Note:
1. This file is generated by the javah command. To ensure the normal operation of JNI, do not directly modify the content of this file. JNI developers only need to implement the defined functions using C/C ++.
2. This is the two C function prototypes generated by the javah command, which are generated based on the local methods declared in the Java class. View the comments of the function prototype. You can see the local methods in the Java code corresponding to the function prototype. The comments indicate three elements: Class Name, local method, and local method signature.
Next, let's analyze the function prototype: Both jniexport and jnicall are JNI keywords, indicating that the function is to be called by JNI. The function prototype must have these two keywords before JNI can call the function normally. In fact, jniexport and jnicall are both macro-defined keywords in the jdk_home/include/Win32/jni_md.h file (under the window platform.
Observe the function prototype name and find that the function name follows certain naming rules: the function name supported by JNI is "Java _ classname_local method name ". By using the function name, we can infer which local method of the Java class corresponds to the JNI local function.
The generated function prototype contains two default parameters: jnienv * And jobject. functions supporting JNI must contain these two common parameters. The first parameter jnienv * is the JNI interface pointer used to call various JNI functions in the JNI table (the JNI function here refers to the basic function set provided in JNI ); the second parameter jobject is also a Java local method provided by JNI, which is used to access Java objects in C code. This parameter stores a reference of the object that calls the local method.
In JNI programming, data exchange is often performed between Java programs and C/C ++ functions. If one method is not provided to eliminate the differences in data types between the two languages, then the program will not run normally, and the running reliability will not be guaranteed. JNI provides a set of Java local types corresponding to the Java data type, so that the local language can use the Java data type, as shown in the following table:
Java type |
Local type |
Byte (BIT) |
Boolean |
Jboolean |
8, |
Byte |
Jbyte |
8 |
Char |
Jchar |
16, |
Short |
Jshort |
16 |
Int |
Jint |
32 |
Long |
Jlong |
64 |
Float |
Jfloat |
32 |
Double |
Jdouble |
64 |
Void |
Void |
N/ |
The above Java local type is defined in the jdk_home/include/JNI. h file. In addition, the Java local type also provides three other types, corresponding to the Java class, object and string reference data (In addition, there are several reference types, if you are interested, you can refer to the relevant materials ).
Java reference type |
Java local type |
Class |
Jclass |
Object |
Jobject |
String |
Jstring |
Step 4: CompileCCode
After the C function prototype is generated, write the hellojni. c file to implement the JNI local function. First, define in hellojni. copy the function prototype in the H header file to hellojni. c. Note that in the header file generated using the javah name, the function parameter only specifies the parameter type and does not provide the parameter name. Therefore, after copying the function prototype and starting to implement the C function, you must specify a specific parameter name after the parameter type.
The written hellojni. C code is as follows:
# Include "hellojni. H "# include <stdio. h> // Add the jniexport void jnicall java_hellojni_printhello (jnienv * ENV, jobject OBJ) {printf ("Hello world! \ N "); return;} jniexport void jnicall java_hellojni_printstring (jnienv * ENV, jobject OBJ, jstring string) {// convert Java string to C string const char * STR = (* env)-> getstringutfchars (ENV, String, 0); printf ("% s! \ N ", STR); return ;}
Getstringutfchars () is a JNI function used to convert a Java string to a C string. JNI provides a variety of JNI functions to process the conversion between C strings and Java strings. For details, refer:
Step 5: generateCShared Library
After compiling hellojni. C, use the compiler to compile it into the hellojni. dll file. Here we use visual c ++ 2008 express editions. After installation, run the Visual Studio 2008 command prompt and enter the compilation command:
CL-I "F: \ Java \ jdk1.7.0 \ include"-I "F: \ Java \ jdk1.7.0 \ include \ Win32"-LD hellojni. C-fehellojni. dll
The execution result is:
Instructions:
CL: Visual C ++ compilation command
-I <dir>: add the directory path of the header file to be retrieved. <dir>
To retrieve the header file, add the following directory
JNI. H (<jdk_hone> \ include)
Jni_md.h (jdk_hone> \ include \ Win32)
-Ld: Create DLL
-Fe <File Name>: Specifies the name of the compilation result file.
Step 6: RunJavaProgram
Run the Java command to run the hellojni class.