Java provides Java Native Interface(JNI) to enable developers to write programs which can utilize the underlying native libraries of the operating system. The benefits of writing native code are that they normally provide better performance compared to Java codes. Sometimes if you want to utilize some system specific functions you may also want to use JNI. One main drawback of writing native code is that your application may not be platform independent anymore. This is not what Java is designed for.
Today we will show you a small tutorial on how to write a Java program calling native code. To write the native code, we will use C language and Visual Studio as the IDE. Let's say we want to call a native function callMe() to print a message "I am called".
First let's write the Java code which will call the callMe() function. The Java code is just a normal Java program with an additional native call signature.
public class JNISample { public native void callMe(); public static void main(String[] atgs){ new JNISample().callMe(); // It will print "I am called" } }
Notice that the method signature has a modifier native which indicates it is a native method. But when you run the program, you will see there is a java.lang.UnsatisfiedLinkError thrown. This is because it cannot find the native method in its current classpath. We will fix this problem later after complete writing the native code.
Now let's write the native code which will actually print the message "I am called". Open Visual Studio, here we use Visual Studio 2013 to do the demo. then do following to create the native project.
- Create new EMPTY project, give it a name "JNISample"
- Start to configure the project, go to "PROJECT" -> " Properties..."
- Since it's a native library, so we want to create a dll instead of an exe, so the first thing to configure is selecting "General", on the right panel, find "Configuration Type" and set it to Dynamic Library (.dll)
- Move to option "VC++ Directories", on right panel, select "Include Directories", then click "" to add the include directory. Here we need to include the JDK include directories so that the native code can access the Java include header files such as jni.h. The two include directories are <JDK_HOME>/include and <JDK_HOME>/include/win32.
- Click "Apply". We are done with the settings.
Next start to create a header file named JNISample.h with below content.
#include #ifndef _Included_JNISample #define _Included_JNISample /* * Class: JNISample * Method: callMe * Signature: ()V */ JNIEXPORT void JNICALL Java_JNISample_callMe (JNIEnv *, jobject); #endif
Note you need to include jni.h which is the header file for Java Native Interface. Then create the prototype for the native method. To know what the correct of the method name is, you may refer to Oracle Documentation.
Then creating the C source file JNISample.c with below code.
#include #include "JNISample.h" JNIEXPORT void JNICALL Java_JNISample_callMe (JNIEnv *env, jobject obj){ printf("I am called"); return; }
This is a pretty simple C program which just calls standard C's printf() function. Now build the project and a dll named JNISample.dll will be generated in project home. Copying this dll into the classpath of the Java project.
Now let's solve the earlier error when running the Java program, this is because we don't load the dynamica library containing the native method we want to call. To load the library, we need to add below block in our JNISample.java.
static{ System.loadLibrary("JNISample"); }
The complete Java class will be :
public class JNISample { static{ System.loadLibrary("JNISample"); // Load the dynamic library } public native void callMe(); public static void main(String[] atgs){ new JNISample().callMe(); // It will print "I am called" } }
Now run the program, you will see the output:
I am called
If you see this, you have made the native code work.