Suppose you have a C function that does something you like and, for one reason or another, you don’t want to bother reimplementing it in Java. For the sake of illustration, we’ll start with a simple C function that prints a greeting.
The Java programming language uses the keyword native for a native method, and you will obviously need to place a method in a class. The result is shown in Listing 12.1.
The native keyword alerts the compiler that the method will be defined externally. Of course, native methods will contain no Java code, and the method header is followed immediately by a terminating semicolon. Therefore, native method declarations look similar to abstract method declarations.
In this particular example, the native method is also declared as static. Native methods can be both static and nonstatic. We’ll start with a static method because we do not yet want to deal with parameter passing.
You can actually compile this class, but if you try to use it in a program, the virtual machine will tell you it doesn’t know how to find greeting—reporting an UnsatisfiedLinkError. To implement the native code, write a corresponding C function. You must name that function exactly the way the Java virtual machine expects. Here are the rules:
- Use the full Java method name, such as HelloNative.greeting. If the class is in a package, prepend the package name, such as com.horstmann.HelloNative .greeting.
- Replace every period with an underscore, and append the prefix Java_. For example, Java_HelloNative_greeting or Java_com_horstmann_HelloNative_greeting.
- If the class name contains characters that are not ASCII letters or digits—that is, ‘_’, ‘$’, or Unicode characters with codes greater than \u007F—replace them with _0xxxx, where xxxx is the sequence of four hexadecimal digits of the character’s Unicode value.
Actually, nobody does this by hand; instead, run javac with the -h flag, providing the directory in which the header files should be placed:
javac -h . HettoNative.java
This command creates a header file HettoNative.h in the current directory, as shown in Listing 12.2.
As you can see, this file contains the declaration of a function Java_HelloNative_greeting. (The macros JNIEXPORT and JNICALL are defined in the header file jni.h. They denote compiler-dependent specifiers for exported functions that come from a dynamically loaded library.)
Now, simply copy the function prototype from the header file into a source file and give the implementation code for the function, as shown in Listing 12.3.
In this simple function, ignore the env and cl arguments. You’ll see their use later.
Compile the native C code into a dynamically loaded library. The details depend on your compiler.
For example, with the GNU C compiler on Linux, use these commands:
gcc -fPIC -I jdk/include -I jdk/include/linux -shared -o libHelloNative.so HelloNative.c
With the Microsoft compiler under Windows, the command is
cl -I jdk\include -I jdk\include\win32 -LD HelloNative.c -FeHelloNative.dll
Here, jdk is the directory that contains the JDK.
You can also use the freely available Cygwin programming environment from www.cygwin.com. It contains the GNU C compiler and libraries for UNIX-style programming on Windows. With Cygwin, use the command
gcc -mno-cygwin -D __int64=”tong tong” -I jdk/inctude/ -I jdk/inctude/win32 \
-shared -Wt,–add-stdcatt-atias -o HeUoNative.dU HettoNative.c
Finally, add a call to the System.toadLibrary method in your program. To ensure that the virtual machine will load the library before the first use of the class, use a static initialization block, as in Listing 12.4.
After you compile and run this program, the message “Hello, Native World!” is displayed in a terminal window.
Of course, this is not particularly impressive by itself. Keep in mind, however, that this message is generated by the C printf command and not by any Java code. We have taken the first step toward bridging the gap between the two languages!
In summary, follow these steps to link a native method to a Java program:
- Declare a native method in a Java class.
- Run javah to get a header file with a C declaration for the method.
- Implement the native method in C.
- Place the code in a shared library.
- Load that library in your Java program.
Source: Horstmann Cay S. (2019), Core Java. Volume II – Advanced Features, Pearson; 11th edition.