I have just been familiar with Android and Java platforms, but I still don't know much about JNI. So I have reposted an article from csdn so that I can understand JNI, I would also like to share with you.
JNIYesJava Native Interface. Since Java 1.1, the Java Native Interface (JNI) standard has become part of the Java platform. It allows Java code to interact with code written in other languages. JNI was initially designed for locally compiled languages, especially C and C ++, but it does not prevent you from using other languages, as long as the call conventions are supported.
Using Java to interact with locally compiled code usually results in loss of platform portability. However, in some cases, this is acceptable or even necessary. For example, you can use old libraries to interact with hardware and operating systems, or to improve program performance. The JNI standard should at least ensure that local code can work under any Java Virtual Machine implementation.
I. design objective of JNI (Java Native Interface)
· The standard Java class library may not support the platform-dependent features needed by your application.
· You may already have a library or application written in another programming language and you wish to make it accessible to Java applications
· You may want to implement a small portion of time-critical code in a lower-level programming language, such as assembly, and then have your Java application call these functions
Ii. Writing steps of JNI (Java Native Interface)
· Compile a Java class with native declarations
· Use the javac command to compile the compiled Java class
· Use javah? JNI Java class names generate header files with the extension H
· Use C/C ++ to implement local methods
· Generate a dynamic connection library for files written in C/C ++
1) Compile a Java program:
The following uses helloworld as an example.
Code 1:
Class helloworld {
Public native void displayhelloworld ();
Static {
System. loadlibrary ("hello ");
}
Public static void main (string [] ARGs ){
New helloworld (). displayhelloworld ();
}
}
Declare native method: If you want to use a method as a local method, you must declare the method to native and cannot implement it. The parameters and return values of the method are described later.
Load dynamic library: system. loadlibrary ("hello"); load the dynamic library (we can understand as follows: Our method displayhelloworld () is not implemented, but we use it directly below, therefore, it must be initialized before use.) Static blocks are usually used for loading. Note that the parameter "hello" of system. loadlibrary (); is the name of the dynamic library.
The main () method is the function entry point.
2) Compile
Javac helloworld. Java
3) generate a header file with the extension of H
Javah helloworld
Header file content:
/* Do not edit this file-it is machine generated */
# Include
/* Header for class helloworld */
# Ifndef _ included_helloworld
# DEFINE _ included_helloworld
# Ifdef _ cplusplus
Extern "C "{
# Endif
/*
* Class: helloworld
* Method: displayhelloworld
* Signature: () V
*/
Jniexport void jnicall java_helloworld_displayhelloworld (jnienv *, jobject );
# Ifdef _ cplusplus
}
# Endif
# Endif
(Here we can understand it as follows: This H file is equivalent to our interface in Java. Here we declare a java_helloworld_displayhelloworld (jnienv *, jobject); method, then implement this method in our local method, that is to say, the method name we used when writing the C/C ++ program must be consistent with the method name here ).
4) Compile a local method (C/C ++ Program)
Implement the same method as the method name declared in the header file generated by the javah command.
Code 2:
1 # include "JNI. H"
2 # include "helloworld. H"
3 # include ......
4 jniexport void jnicall java_helloworld_displayhelloworld (jnienv * ENV, jobject OBJ)
{
Printf ("Hello world! ");
Return;
}
Note that the JNI. H (this file can be found under the % java_home %/include folder) file introduction, because the types of jnienv and jobject in the program are defined in this header file;
In addition, the helloworld. h header file introduction (I understand this as follows: It is equivalent that we can declare an interface when writing a Java program. Here we will introduce helloworld. h. The methods declared in the header file are implemented. Of course not necessarily ). SaveHelloworldimpl. cOK.
5) generate a dynamic library
Here, we use Windows as an example. We need to generateDLLFile. In the helloworldimpl. c folder, use the VC compiler Cl to generate.
The command line is as follows: CL-I % java_home % \ include-I% Java_home %\ Include \ Win32-LD helloworldimp. C-fehello. dll
Note: The generated DLL file name is configured after option-Fe. Here is hello, because the name we use when loadlibary is hello in the helloworld. Java file. Of course, after modification, it also needs to be modified. In addition, you need to add the-I % java_home % \ include \ Win32 parameter, because the JNI. H file is introduced when compiling the local method in step 4.
6) run the program
Java helloworld is OK.
Iii. Example of JNI (Java Native Interface)
The following is a simple example to implement the function of printing a sentence, but the printf of C is used for the final implementation. The JNI interface provided to Java generally includes a so file (which encapsulates the implementation of the c function) and a Java file (the class that needs to call the path ).
1. the purpose of JNI is to enable the Java method to call some functions implemented by C. For example, in the following Java class, a local function testjni (usually declared as private native) needs to be called ), first, create the weiqiong file. java, the content is as follows:
Class weiqiong
{
Static
{
System. loadlibrary ("testjni"); // load the static library, where the test function is implemented
}
Private native void testjni (); // declare a local call
Public void test ()
{
Testjni ();
}
Public static void main (string ARGs [])
{
Weiqiong Haha = new weiqiong ();
Haha. Test ();
}
}
2. Then run javac weiqiong. java. If no error is reported, a weiqiong. Class is generated.
3. Run javah weiqiong to generate a weiqiong. h file. The declaration of a function is as follows:
Jniexport void jnicall java_weiqiong_testjni (jnienv *, jobject );
4. Create the file testjni. C and implement the above function. The content is as follows:
# Include "JNI. H"
# Include weiqiong. hjniexport void jnicall java_weiqiong_testjni (jnienv * ENV, jobject OBJ)
{
Printf ("Haha --------- go into C !!! ");
}
5. to generate the. So file, create the MAKEFILE file as follows:
Libtestjni. So: testjni. O makefile
Gcc-wall-rdynamic-shared-O libtestjni. So testjni. o
Testjni. O: testjni. c weiqiong. h
Gcc-wall-C testjni. C-I./-I/usr/Java/j2sdk1.4.0/include-I/usr/Java/j2sdk1.4.0/include/Linux
CL:
Rm-RF *. O *. So
Note: The tab is blank before GCC. The j2sdk directory is written according to the specific version of j2sdk installed by yourself. The generated so file name must be "lib" before the parameter name of loadlibrary ".
6. Export LD_LIBRARY_PATH =., and set the library path to the current directory so that the so file can be found in the Java file. The general practice is to copy the so file to the local LD_LIBRARY_PATH directory.
7. execute Java weiqiong and print the result: "Haha --------- go into C !!!"
Iv. Issues in JNI (Java Native Interface) calls
I had some questions when I used JNI for the first time. Later I was able to solve these problems one by one. The following are my notes:
1. How is Java and C interconnected?
In fact, the main reason for the inability to communicate is the data type problem. JNI solves this problem. For example, the jstring data type in the C file is the string object passed in by Java, after the conversion of the JNI function, it can become the char * of C *.
The following table lists the corresponding data type relationships:
Java type |
Local C type |
Description |
Boolean |
Jboolean |
Unsigned, 8-bit |
Byte |
Jbyte |
Unsigned, 8-bit |
Char |
Jchar |
Unsigned, 16-bit |
Short |
Jshort |
Signed, 16-bit |
Int |
Jint |
Signed, 32-bit |
Long |
Jlong |
Signed, 64-bit |
Float |
Jfloat |
32-bit |
Double |
Jdouble |
64-bit |
Void |
Void |
N/ |
JNI also contains many reference types corresponding to different Java objects.
2. How to convert the string parameter passed in by Java to the char * of C and then use it?
The string parameter passed in by Java is converted to the Data Type of jstring by JNI in the C file. Declare char * test in the C file, and then test = (char *) (* env) -> getstringutfchars (ENV, jstring, null); Note: after the test is used, the VM platform-related code is notified that no access is required (* env)-> releasestringutfchars (ENV, jstring, test );
3. Pass the buffer of a char * obtained in C to Java?
If this char * is a general string, it can be returned as a string. If it is a buffer containing '\ 0', it is best to use bytearray for outgoing transmission, because the copy length can be set. If it is copied to string, it may be truncated to' \ 0.
There are two ways to pass the data:
One is to directly create a byte array in JNI, and then call the function (* env)-> setbytearrayregion (ENV, bytearray, 0, Len, buffer ); copy the buffer value to bytearray, and the function can return bytearray directly.
One is the return error code. The data is transmitted as the parameter, but the basic data type of Java is to pass the value, and the object is to pass the reference, use a class package to package the byte array to be transmitted, as shown below:
Class retobj
{
Public byte [] bytearray;
}
This object is transmitted as the retobj parameter of the function. The following function is used to assign values to the byte array in retobj to facilitate the transfer. The Code is as follows:
Jclass CLS;
Jfieldid FID;
Jbytearray bytearray;
Bytearray = (* env)-> newbytearray (ENV, Len );
(* Env)-> setbytearrayregion (ENV, bytearray, 0, Len, buffer );
CLS = (* env)-> getobjectclass (ENV, retobj );
FID = (* env)-> getfieldid (ENV, CLS, "retbytes", "[B"]);
(* Env)-> setobjectfield (ENV, retobj, FID, bytearray );
4. I don't know how much buffer is occupied. How can I transfer it out?
In the jni c file, the new output space is passed out. If Java data is not initialized, point to the space passed out.
V. Processing of imported Java data in JNI
If bytearray is input, perform the following processing to obtain the buffer:
Char * tmpdata = (char *) (* env)-> getbytearrayelements (ENV, bytearray, null );
(* Env)-> releasebytearrayelements (ENV, bytearray, tmpdata, 0 );
6. Data processing problems after Java calls the local Interface
1. If the data obtained by Java is string, you can directly process it.
2. if the result is bytearray, perform the following processing:
Datainputstream in = new datainputstream (New bytearrayinputstream (bytearray ));
Byte [] byte1 = new byte [36];
In. Read (byte1, 0, 36 );
String string = new string (byte1 );
System. Out. println ("read the first field:" + String); reprinted address: http://blog.csdn.net/drean725/archive/2007/05/07/1599116.aspx