JNI呼び出し
12761 ワード
Figure 2.1 illustrates the process for using JDK or Java 2 SDK releases to write a simple Java application that calls a C function to print " Create a class ( Use Use Write the C implementation ( Compile the C implementation into a native library, creating Run the
The remainder of this chapter explains these steps in detail.
Figure 2.1 Steps in Writing and Running the "Hello World"Program
2.2 Declare the Native Method
You begin by writing the following program in the Java programming language. The program defines a class named
The
There are two differences between the declaration of a native method such as
Before the native method
We define a
2.3 Compile the
After you have defined the
This command will generate a
2.4 Create the Native Method Header File
Next we will use the
The name of the header file is the class name with a "
Ignore the
2.5 Write the Native Method Implementation
The JNI-style header file generated by
The implementation of this native method is straightforward. It uses the
The C program includes three header files:
2.6 Compile the C Source and Create a Native Library
Remember that when you created the
Now that all the necessary C code is written, you need to compile
Different operating systems support different ways to build native libraries. On Solaris, the following command builds a shared library called
The
The
2.7 Run the Program
At this point, you have the two components ready to run the program. The class file (
Because the
You should see the following output:
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:
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, the
The equivalent command in the C shell (
If you are running on a Windows 95 or Windows NT machine, make sure that
In Java 2 SDK 1.2 release, you can also specify the native library path on the
The "
Hello World!
". The process consists of the following steps: HelloWorld.java
) that declares the native method. 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. javah
-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. HelloWorld.c
) of the native method. Hello-World.dll
or libHello-World.so
. Use the C compiler and linker available on the host environment. HelloWorld
program using the java
runtime interpreter. Both the class file ( HelloWorld.class
) and the native library ( HelloWorld.dll
or libHelloWorld.so
) are loaded at runtime. The remainder of this chapter explains these steps in detail.
Figure 2.1 Steps in Writing and Running the "Hello World"Program
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 the HelloWorld
class. The Java virtual machine automatically runs the static initializer before invoking any methods in the HelloWorld
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 called HelloWorld.dll
on Win32, or libHelloWorld.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 the Hello-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 named HelloWorld.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 for Java_HelloWorld_print
, which is the C function that implements the HelloWorld
. print
method:
JNIEXPORT void JNICALL
Java_HelloWorld_print (JNIEnv *, jobject);
Ignore the
JNIEXPORT
and JNICALL
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 a JNIEnv
interface pointer. The second argument is a reference to the HelloWorld
object itself (sort of like the "this"pointer in C++). We will discuss how to use the JNIEnv
interface pointer and the jobject
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 the Hello-World.print
method in a C file HelloWorld.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 includes stdio.h
because it uses the printf
function. HelloWorld.h
-- The header file that you generated using javah
. It includes the C/C++ prototype for the Java_HelloWorld_print function. 2.6 Compile the C Source and Create a Native Library
Remember 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 compile
Hello-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. On Win32, 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 that HelloWorld.dll
is linked with the Win32 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, the
LD_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 the libHelloWorld.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 the LD_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 that
HelloWorld.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 the java.library.path
property to ".
"instructs the Java virtual machine to search for native libraries in the current directory.