You wish to call native C/C++ functions from Java, either for efficiency or to access hardware- or system-specific features.
Java lets you load native or compiled code into your Java program. Why would you want to do such a thing? One reason might be to access OS-dependent functionality. Another is speed: native code will likely run faster than Java, at least at present. Like everything else in Java, this mechanism is subject to security restrictions; for example, applets are not allowed to access native code.
The native code language bindings are defined for code that has been written in the C or C++ language. If you need to access a language other than C/C++, write a bit of C/C++ and have it pass control to other functions or applications, using any mechanism defined by your operating system.
Due to such system-dependent features as the interpretation of header files and the allocation of the processor’s general-purpose registers, your native code may need to be compiled by the same C compiler used to compile the Java runtime for your platform. For example, on Solaris you can use SunPro C, or maybe gcc. On Win32 platforms, use Microsoft Visual C++ Version 4.x or higher (32 bit). For other platforms, see your Java vendor’s documentation.
Also note that the details in this section are for Java 1.1’s Java Native Interface (JNI) that differs in some details from 1.0 and from Microsoft’s native interface.
The steps to call native code are summarized in the following sidebar and detailed below.
The first step is to write Java code that calls a native method. To
do this, use the keyword
native
to indicate that the method is native, and
provide a static code block that loads your native method using
System.loadLibrary( )
. (The dynamically loadable module is
created in Step 5.) Static blocks are executed when the class
containing them is loaded; loading the native code here ensures it is
in memory when needed!
Object variables that your native code may modify should carry the
volatile
modifier. The file
HelloWorld.java
, shown in Example 26-7,
is a good starting point.
Example 26-7. HelloWorld.java
/** * A trivial class to show Java Native Interface 1.1 usage from Java. */ public class HelloWorld { int myNumber = 42; // used to show argument passing // declare native class public native void displayHelloWorld( ); // Application main, call its display method public static void main(String[] args) { System.out.println("HelloWorld starting; args.length="+ args.length+"..."); for (int i=0; i<args.length; i++) System.out.println("args["+i+"]="+args[i]); HelloWorld hw = new HelloWorld( ); hw.displayHelloWorld( ); // call the native function System.out.println("Back in Java, "myNumber" now " + hw.myNumber); } // Static code blocks are executed once, when class file is loaded static { System.load("libhello.so"); } }
The second step is simple; just use javac HelloWorld as you normally would. You probably won’t get any compilation errors on a simple program like this; if you do, correct them and try the compilation again.
Next, you need to create an
.h
file. Use javah
to produce files:
javah -jni HelloWorld // produces HelloWorld.h
The -jni
is required; without it, you get
incompatible 1.0 output.
The .h
file produced is a
“glue” file, not really meant
for human consumption and particularly not for editing. But by
inspecting the resulting .h
file, you’ll
see that the C method’s name is composed of the name
Java
, the package name (if any), the class name,
and the method name:
void Java_HelloWorld_displayHelloWorld(JNIEnv *env, jobject this);
Then, create a C function that does the work. You must use the same
function signature as is used in the .h
file:
void Java_HelloWorld_displayHelloWorld(JNIEnv *env, jobject this) {
This function can do whatever it wishes. Note that it is passed two
arguments: a JVM environment, and a handle for the
this
object. Table 26-2 shows
the correspondence between Java types and the C types (JNI types)
used in the C code.
Table 26-2. Java and JNI types
Example 26-8 is a complete
C native implementation. Passed an object
of type HelloWorld
, it increments the integer
myNumber
contained in the object.
Example 26-8. HelloWorld.c
#include <jni.h> #include "HelloWorld.h" #include <stdio.h> /* * This is the 1.1 implentation of displayHelloWorld. */ void Java_HelloWorld_displayHelloWorld(JNIEnv *env, jobject this) { jfieldID fldid; jint n, nn; (void)printf("Hello from a Native Method "); if (this == NULL) { fprintf(stderr, "Input pointer is null! "); return; } if ((fldid = (*env)->GetFieldID(env, (*env)->GetObjectClass(env, this), "myNumber", "I")) == NULL) { fprintf(stderr, "GetFieldID failed"); return; } n = (*env)->GetIntField(env, this, fldid); /* retrieve myNumber */ printf(""myNumber" value is %d ", n); (*env)->SetIntField(env, this, fldid, ++n); /* increment it! */ nn = (*env)->GetIntField(env, this, fldid); printf(""myNumber" value now %d ", nn); /* make sure */ return; }
Finally, you compile the C code into a loadable object. Naturally, the details depend on platform, compiler, etc. For example, on Windows 95:
> set JAVAHOME=C:java # or wherever > set INCLUDE=%JAVAHOME%include;%INCLUDE% > set LIB=%JAVAHOME%lib;%LIB% > cl HelloWorld.c -Fehello.dll -MD -LD javai.lib
$ export JAVAHOME=/local/java # or wherever $ cc -I$JAVAHOME/include -I$JAVAHOME/include/solaris -G HelloWorld.c -o libhello.so
Example 26-9 is a makefile for Unix.
Example 26-9. Unix makefile
# Makefile for the 1.1 Java Native Methods examples for # Learning Tree International Course 471/478. # Has been tested on Solaris both with "gcc" and with SunSoft "cc". # On other platforms it will certainly need some tweaking; please # let me know how much! :-) # Configuration Section CSRCS = HelloWorld.c JAVAHOME = /local/jdk1.1.2 INCLUDES = -I$(JAVAHOME)/include -I$(JAVAHOME)/include/solaris LIBDIR = $(JAVAHOME)/lib/sparc/green_threads CLASSPATH = $(JAVAHOME)/lib/classes.zip:. all: testhello testjavafromc # This part of the Makefile is for C called from Java, in HelloWorld testhello: hello.all @echo @echo "Here we test the Java code "HelloWorld" that calls C code." @echo LD_LIBRARY_PATH=`pwd`:. java HelloWorld hello.all: HelloWorld.class libhello.so HelloWorld.class: HelloWorld.java javac HelloWorld.java HelloWorld.h: HelloWorld.class javah -jni HelloWorld HelloWorld.o:: HelloWorld.h libhello.so: $(CSRCS) HelloWorld.h $(CC) $(INCLUDES) -G $(CSRCS) -o libhello.so # This part of the Makefile is for Java called from C, in javafromc testjavafromc: javafromc.all hello.all @echo @echo "Now we test HelloWorld using javafromc instead of java" @echo LD_LIBRARY_PATH="$(LIBDIR):." CLASSPATH="$(CLASSPATH)" ./javafromc HelloWorld @echo @echo "That was, in case you didn't notice, C->Java->C. And," @echo "incidentally, a replacement for JDK program "java" itself!" @echo javafromc.all: javafromc javafromc: javafromc.o $(CC) -L$(LIBDIR) javafromc.o -ljava -o $@ javafromc.o: javafromc.c $(CC) -c $(INCLUDES) javafromc.c clean: rm -f core *.class *.o *.so HelloWorld.h clobber: clean rm -f javafromc
And you’re done! Just run the Java interpreter on the class file containing the main program. Assuming that you’ve set whatever system-dependent settings are necessary (possibly including both CLASSPATH and LD_LIBRARY_PATH or its equivalent), the program should run as follows:
C> java HelloWorld Hello from a Native Method // from C "myNumber" value is 42 // from C "myNumber" value now 43 // from C Value of myNumber now 43 // from Java
Congratulations! You’ve called a native method. However, you’ve given up portability; the Java class file now requires you to build a loadable object for each operating system and hardware platform. Multiply {MS-Windows 95/98, MS-Windows CE, Me, and NT, MacOS, Sun Solaris, HP/UX, Linux, OpenBSD, NetBSD, FreeBSD} times {Intel, SPARC, PowerPC, HP-PA, Sun3} and you begin to see the portability issues. Your native code can be used in server code and desktop applications, but is normally not permitted in web browsers.
Beware that problems with your native code can and will crash the runtime process right out from underneath the Java Virtual Machine. The JVM can do nothing to protect itself from poorly written C/C++ code. Memory must be managed by the programmer; there is no automatic garbage collection of memory obtained by the system runtime allocator. You’re dealing directly with the operating system and sometimes even the hardware, so, “Be careful. Be very careful.”
3.133.152.198