Have a look at Java Native Interface: Getting Started.
2.1 Overview
[…] write a simple Java application that calls a C function to print
“Hello World!”. The process consists of the following steps:Create a class (HelloWorld.java) that declares the native method. Use
javac to compile the HelloWorld source file, resulting in the class
file HelloWorld.class. The javac compiler is supplied with JDK or Java
2 SDK releases. Usejavah -jni
to generate a C header file
(HelloWorld.h
) containing the function prototype for the native method
implementation. The javah tool is provided with JDK or Java 2 SDK
releases. Write the C implementation (HelloWorld.c
) of the native
method. Compile the C implementation into a native library, creating
Hello-World.dll
orlibHello-World.so
. Use the C compiler and linker
available on the host environment. Run the HelloWorld program using
the java runtime interpreter. Both the class file (HelloWorld.class
)
and the native library (HelloWorld.dll
orlibHelloWorld.so
) are loaded
at runtime. The remainder of this chapter explains these steps in
detail.2.2 Declare the Native Method
You begin by writing the following program in the Java programming
language. The program defines a class named HelloWorld that contains a
native method, print.class HelloWorld { private native void print(); public static void main(String[] args) { new HelloWorld().print(); } static { System.loadLibrary("HelloWorld"); } }
The HelloWorld class definition begins with the declaration of the print native method. This is followed by a main method that
instantiates the Hello-World class and invokes the print native method
for this instance. The last part of the class definition is a static
initializer that loads the native library containing the
implementation of the print native method.There are two differences between the declaration of a native method
such as print and the declaration of regular methods in the Java
programming language. A native method declaration must contain the
native modifier. The native modifier indicates that this method is
implemented in another language. Also, the native method declaration
is terminated with a semicolon, the statement terminator symbol,
because there is no implementation for native methods in the class
itself. We will implement the print method in a separate C file.Before the native method print can be called, the native library that
implements print must be loaded. In this case, we load the native
library in the static initializer of theHelloWorld
class. The Java
virtual machine automatically runs the static initializer before
invoking any methods in theHelloWorld
class, thus ensuring that the
native library is loaded before the print native method is called.We define a main method to be able to run the
HelloWorld
class.
Hello-World.main
calls the native method print in the same manner as
it would call a regular method.
System.loadLibrary
takes a library name, locates a native library that
corresponds to that name, and loads the native library into the
application. We will discuss the exact loading process later in the
book. For now simply remember that in order for
System.loadLibrary("HelloWorld")
to succeed, we need to create a
native library calledHelloWorld.dll
on Win32, orlibHelloWorld.so
on
Solaris.2.3 Compile the HelloWorld Class
After you have defined the HelloWorld class, save the source code in a
file called HelloWorld.java. Then compile the source file using the
javac compiler that comes with the JDK or Java 2 SDK release:javac HelloWorld.java
This command will generate a
HelloWorld.class
file in the current directory.2.4 Create the Native Method Header File
Next we will use the
javah
tool to generate a JNI-style header file
that is useful when implementing the native method in C. You can run
javah
on theHello-World
class as follows:javah -jni HelloWorld
The name of the header file is the class name
with a “.h
” appended to the end of it. The command shown above
generates a file namedHelloWorld.h
. We will not list the generated
header file in its entirety here. The most important part of the
header file is the function prototype forJava_HelloWorld_print
, which
is the C function that implements the HelloWorld.print method:JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *, jobject);
Ignore the
JNIEXPORT
andJNICALL
macros for now. You may have noticed
that the C implementation of the native method accepts two arguments
even though the corresponding declaration of the native method accepts
no arguments. The first argument for every native method
implementation is aJNIEnv
interface pointer. The second argument is a
reference to theHelloWorld
object itself (sort of like the “this
”
pointer in C++). We will discuss how to use theJNIEnv
interface
pointer and thejobject
arguments later in this book, but this simple
example ignores both arguments.2.5 Write the Native Method Implementation
The JNI-style header file generated by
javah
helps you to write C or
C++ implementations for the native method. The function that you write
must follow the -prototype specified in the generated header file. You
can implement theHello-World.print
method in a C fileHelloWorld.c
as
follows:#include <jni.h> #include <stdio.h> #include "HelloWorld.h" JNIEXPORT void JNICALL Java_HelloWorld_print(JNIEnv *env, jobject obj) { printf("Hello World!\n"); return; }
The implementation of this native method is straightforward. It uses the printf function to display the string “Hello World!” and then returns. As mentioned before, both arguments, the
JNIEnv
pointer and the reference to the object, are ignored.The C program includes three header files:
jni.h
— This header file provides information the native code needs
to call JNI functions. When writing native methods, you must always
include this file in your C or C++ source files.
stdio.h
— The code
snippet above also includesstdio.h
because it uses theprintf
function.
HelloWorld.h
— The header file that you generated using
javah
. It includes the C/C++ prototype for theJava_HelloWorld_print
function.
2.6 Compile the C Source and Create a Native LibraryRemember that when you created the
HelloWorld
class in the
HelloWorld.java
file, you included a line of code that loaded a native
library into the program:System.loadLibrary("HelloWorld");
Now that all the necessary C code
is written, you need to compileHello-World.c
and build this native
library.Different operating systems support different ways to build native
libraries. On Solaris, the following command builds a shared library
called libHello-World.so:cc -G -I/java/include -I/java/include/solaris HelloWorld.c -o libHelloWorld.so
The -G option instructs the C compiler to generate a shared library instead of a regular Solaris
executable file. Because of the limitation of page width in this book,
we break the command line into two lines. You need to type the command
in a single line, or place the command in a script file. OnWin32
, the
following command builds a dynamic link library (DLL)HelloWorld.dll
using the Microsoft Visual C++ compiler:cl -Ic:\java\include -Ic:\java\include\win32 -MD -LD HelloWorld.c -FeHelloWorld.dll
The
-MD
option ensures thatHelloWorld.dll
is linked with theWin32
multithreaded C library.
The-LD
option instructs the C compiler to generate a DLL instead of a
regular Win32 executable. Of course, on both Solaris and Win32 you
need to put in the include paths that reflect the setup on your own
machine.2.7 Run the Program
At this point, you have the two components ready to run the program.
The class file (HelloWorld.class
) calls a native method, and the
native library (Hello-World.dll
) implements the native method.Because the
HelloWorld
class contains its own main method, you can run
the program on Solaris or Win32 as follows:java HelloWorld
You should see the following output:
Hello World!
It is important to set your native library path
correctly for your program to run. The native library path is a list
of directories that the Java virtual machine searches when loading
native libraries. If you do not have a native library path set up
correctly, then you see an error similar to the following:java.lang.UnsatisfiedLinkError: no HelloWorld in library path at java.lang.Runtime.loadLibrary(Runtime.java) at java.lang.System.loadLibrary(System.java) at HelloWorld.main(HelloWorld.java)
Make sure that the native library resides in one of the directories in the native library path.
If you are running on a Solaris system, theLD_LIBRARY_PATH
environment variable is used to define the native library path. Make
sure that it includes the name of the directory that contains the
libHelloWorld.so
file. If thelibHelloWorld.so
file is in the current
directory, you can issue the following two commands in the standard
shell (sh) or KornShell (ksh) to set up theLD_LIBRARY_PATH
environment variable properly:LD_LIBRARY_PATH=. export LD_LIBRARY_PATH
The equivalent command in
the C shell (csh or tcsh) is as follows:setenv LD_LIBRARY_PATH .
If you are running on a Windows 95 or
Windows NT machine, make sure thatHelloWorld.dll
is in the current
directory, or in a directory that is listed in the PATH environment
variable.In Java 2 SDK 1.2 release, you can also specify the native library
path on the java command line as a system property as follows:java -Djava.library.path=. HelloWorld
The “
-D
” command-line option
sets a Java platform system property. Setting thejava.library.path
property to “.
” instructs the Java virtual machine to search for
native libraries in the current directory.