📄 ch05.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"><HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1"><META HTTP-EQUIV="Content-Style-Type" CONTENT="text/css"><META NAME="GENERATOR" CONTENT="Adobe FrameMaker 6.0/HTML Export Filter"><LINK REL="STYLESHEET" HREF="CH05.css" CHARSET="ISO-8859-1" TYPE="text/css"><TITLE> Covered in this Chapter</TITLE></HEAD><BODY BGCOLOR="#ffffff"><P CLASS="CT"><A NAME="pgfId-1087399"></A>5</P><P CLASS="CT"><A NAME="pgfId-1087400"></A>JNI Technology</P><P CLASS="Body"><A NAME="pgfId-1087401"></A>The Java platform is relatively new, which means there could be times when you will need to integrate programs written in the Java programming language with existing non-Java language services, API toolkits, and programs. The Java platform provides the <A NAME="marker-1087402"></A>Java Native Interface (JNI) to help ease this type of integration. </P><P CLASS="Body"><A NAME="pgfId-1087403"></A>The JNI defines a standard naming and calling convention so the Java virtual machine can locate and invoke native methods. In fact, JNI is built into the Java virtual machine so that the Java virtual machine can invoke local system calls to perform input and output, graphics, networking, and threading operations on the host operating system. </P><P CLASS="Body"><A NAME="pgfId-1087404"></A>This chapter explains how to use JNI in programs written in the Java programming language to call libraries on the local machine, call Java methods from inside native code, and it explains how to create and run a Java virtual machine instance. To show how you can put JNI to use, the examples in this chapter include integrating JNI with the Xbase C++ database API, and show how you can call a mathematical function. <EM CLASS="A">Xbase (</EM><EM CLASS="URL-Footnote">http://www.startech.keller. tx.us/xbase/xbase.html</EM>) has sources you can download. </P><DIV><H4 CLASS="A"><A NAME="pgfId-1087405"></A>Covered in this Chapter</H4><UL><LI CLASS="BL"><A NAME="pgfId-1087406"></A>JNI Example (page 136)</LI><LI CLASS="BL"><A NAME="pgfId-1087407"></A>Strings and Arrays (page 140)</LI><LI CLASS="BL"><A NAME="pgfId-1087408"></A>Other Programming Issues (page 148)</LI></UL></DIV><DIV><H4 CLASS="A"><A NAME="pgfId-1087410"></A><A NAME="42038"></A>JNI Example</H4><P CLASS="Body"><A NAME="pgfId-1087411"></A>The <EM CLASS="CODE">ReadFile</EM> example program shows how you can use the JNI to invoke a native method that makes C function calls to map a file into memory. </P><DIV><H5 CLASS="B"><A NAME="pgfId-1087412"></A>About the Example</H5><P CLASS="Body"><A NAME="pgfId-1087416"></A><A NAME="marker-1087413"></A><A NAME="marker-1087414"></A><A NAME="marker-1087415"></A>You can call code written in any programming language from a program written in the Java programming language by declaring a native Java method, loading the library that contains the native code, and calling the native method. The <EM CLASS="CODE">ReadFile</EM> source code below does exactly that. </P><P CLASS="Body"><A NAME="pgfId-1087417"></A>However, successfully running the program requires a few additional steps beyond compiling the Java programming language source file. After you compile, but before you run the example, you have to generate a header file. The native code implements the function definitions contained in the generated header file and implements the business logic as well. The following sections walk through all the steps. </P><PRE CLASS="CODE"><A NAME="pgfId-1087418"></A>import java.util.*;class ReadFile {//Native method declaration native byte[] loadFile(String name);//Load the library static { System.loadLibrary("nativelib"); } public static void main(String args[]) { byte buf[];//Create class instance ReadFile mappedFile=new ReadFile();//Call native method to load ReadFile.java buf=mappedFile.loadFile("ReadFile.java");//Print contents of ReadFile.java for(int i=0;i<buf.length;i++) { System.out.print((char)buf[i]); } }}</PRE><P CLASS="Body"><A NAME="pgfId-1087419"></A><EM CLASS="Bold">Native Method Declaration. </EM>The <EM CLASS="CODE">native</EM> declaration provides the bridge to run the <EM CLASS="CODE">native</EM> function in the Java virtual machine. In this example, the <EM CLASS="CODE">loadFile</EM><A NAME="marker-1087420"></A> function maps to a C function called <EM CLASS="CODE">Java_ReadFile_loadFile</EM><A NAME="marker-1087421"></A>. The function implementation accepts a <EM CLASS="CODE">String</EM> that represents a file name and returns the contents of that file in the byte array. </P><PRE CLASS="CODE"><A NAME="pgfId-1087422"></A>native byte[] loadFile(String name);</PRE><P CLASS="Body"><A NAME="pgfId-1087425"></A><EM CLASS="Bold">Load the Library. </EM><A NAME="marker-1087423"></A><A NAME="marker-1087424"></A>The library containing the native code implementation is loaded by a call to <EM CLASS="CODE">System.loadLibrary()</EM>. Placing this call in a static initializer ensures this library is only loaded once per class. The library can be loaded outside of the <EM CLASS="CODE">static</EM> block if your application requires it. </P><UL><P CLASS="NOTE"><A NAME="pgfId-1087426"></A>NOTE You might need to configure your environment so the <EM CLASS="CODE">loadLibrary</EM> method can find your native code library. See the section Compile the Dynamic or Shared Object Library for this information.</P></UL><PRE CLASS="CODE-caption"><A NAME="pgfId-1087428"></A>//API Ref: <A NAME="93500"></A>static void loadLibrary(String libraryname)</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087429"></A>static { System.loadLibrary("nativelib");}</PRE><P CLASS="Body"><A NAME="pgfId-1087431"></A><EM CLASS="Bold">Compile the Program. </EM><A NAME="marker-1087430"></A>To compile the program, run the <EM CLASS="CODE">javac</EM> compiler command as you normally would: </P><PRE CLASS="CODE"><A NAME="pgfId-1087432"></A>javac ReadFile.java</PRE><P CLASS="Body"><A NAME="pgfId-1087433"></A>Next, you need to generate a header file with the <EM CLASS="CODE">native</EM> method declaration and implement the <EM CLASS="CODE">native</EM> method to call the C functions for loading and reading a file.</P></DIV><DIV><H5 CLASS="B"><A NAME="pgfId-1087434"></A>Generate the Header File</H5><P CLASS="Body"><A NAME="pgfId-1087437"></A><A NAME="marker-1087435"></A><A NAME="marker-1087436"></A>To generate a header file, run the <EM CLASS="CODE">javah</EM> command on the <EM CLASS="CODE">ReadFile</EM> class. In this example, the generated header file is named <EM CLASS="CODE">ReadFile.h</EM>. It provides a method signature that you have to use when you implement the loadfile <EM CLASS="CODE">native</EM> function. </P><PRE CLASS="CODE"><A NAME="pgfId-1087441"></A><A NAME="marker-1087438"></A><A NAME="marker-1087439"></A><A NAME="marker-1087440"></A>javah -jni ReadFile</PRE></DIV><DIV><H5 CLASS="B"><A NAME="pgfId-1087442"></A>Method Signature</H5><P CLASS="Body"><A NAME="pgfId-1087444"></A>The <EM CLASS="CODE">ReadFile.h</EM><A NAME="marker-1087443"></A> header file defines the interface to map the Java method to the native C function. It uses a method signature to map the arguments and return value of the Java <EM CLASS="CODE">mappedfile.loadFile</EM> method to the <EM CLASS="CODE">loadFile</EM> native method in the <EM CLASS="CODE">nativelib</EM> library. Here is the <EM CLASS="CODE">loadFile</EM> native method mapping (method signature): </P><PRE CLASS="CODE"><A NAME="pgfId-1087445"></A> /* * Class: ReadFile * Method: loadFile * Signature: (Ljava/lang/String;)[B */ JNIEXPORT jbyteArray JNICALL Java_ReadFile_loadFile (JNIEnv *, jobject, jstring);</PRE><P CLASS="Body"><A NAME="pgfId-1087448"></A><A NAME="marker-1087446"></A><A NAME="marker-1087447"></A>The method signature parameters function as follows: </P><UL><LI CLASS="BL"><A NAME="pgfId-1087450"></A><EM CLASS="CODE">JNIEnv *</EM><A NAME="marker-1087449"></A>: A pointer to the JNI environment. This pointer is a handle to the current thread in the Java virtual machine; it contains mapping and other housekeeping information.</LI><LI CLASS="BL"><A NAME="pgfId-1087452"></A><EM CLASS="CODE">jobject</EM><A NAME="marker-1087451"></A>: A reference to the object that called this native code. If the calling method is static, this parameter would be type <EM CLASS="CODE">jclass</EM> instead of <EM CLASS="CODE">jobject</EM>. </LI><LI CLASS="BL"><A NAME="pgfId-1087454"></A><EM CLASS="CODE">jstring</EM><A NAME="marker-1087453"></A>: The parameter supplied to the native method. In this example, it is the name of the file to be read. </LI></UL></DIV><DIV><H5 CLASS="B"><A NAME="pgfId-1087455"></A>Implement the <EM CLASS="B-code">native</EM> Method</H5><P CLASS="Body"><A NAME="pgfId-1087458"></A><A NAME="marker-1087456"></A><A NAME="marker-1087457"></A>In this native C source file, the loadFile definition is a copy and paste of the C declaration contained in <EM CLASS="CODE">ReadFile.h</EM>. The definition is followed by the native method implementation. JNI provides a mapping for both C and C++ by default. </P><PRE CLASS="CODE"><A NAME="pgfId-1087459"></A>/* file nativelib.c */</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087460"></A>#include <jni.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#include <sys/mman.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>JNIEXPORT jbyteArray JNICALL Java_ReadFile_loadFile (JNIEnv * env, jobject jobj, jstring name) { caddr_t m; jbyteArray jb; jboolean iscopy; struct stat finfo;</PRE><PRE CLASS="CODE-caption"><A NAME="pgfId-1087462"></A>//API Ref: <A NAME="80634"></A>const char* GetStringUTFChars(JNIEnv *env, jstring string, jboolean *iscopy)</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087465"></A> <A NAME="marker-1087463"></A><A NAME="GetStringUTFChars"></A>const char *mfile = (*env)->GetStringUTFChars(env, name, &iscopy); int fd = open(mfile, O_RDONLY); if (fd == -1) { printf("Could not open %s\n", mfile); } lstat(mfile, &finfo); m = mmap((caddr_t) 0, finfo.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (m == (caddr_t)-1) { printf("Could not mmap %s\n", mfile); return(0); }</PRE><PRE CLASS="CODE-caption"><A NAME="pgfId-1087467"></A>//API Ref: <A NAME="69100"></A>jbyteArray NewByteArray(JNIEnv *env, jsize length)</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087470"></A> <A NAME="marker-1087468"></A><A NAME="NewByteArray method"></A>jb=(*env)->NewByteArray(env, finfo.st_size);</PRE><PRE CLASS="CODE-caption"><A NAME="pgfId-1087472"></A>//API Ref: <A NAME="83470"></A>SetByteArrayRegion(JNIEnv *env, jbyteArray array, jsize startelement, jsize length, jbyte *buffer)</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087475"></A> <A NAME="marker-1087473"></A><A NAME="SetByteArrayRegion function"></A>(*env)->SetByteArrayRegion(env, jb, 0, finfo.st_size, (jbyte *)m); close(fd); (*env)->ReleaseStringUTFChars(env, name, mfile); return (jb);}</PRE><P CLASS="Body"><A NAME="pgfId-1087476"></A>You can approach calling an existing C function instead of implementing one in one of two ways: </P><OL><LI CLASS="NLS"><A NAME="pgfId-1087477"></A>Map the name generated by JNI to the existing C function name. The Other Programming Issues section (page 148) shows how to map between Xbase database functions and Java programming language code. </LI><LI CLASS="NL"><A NAME="pgfId-1087478"></A>Use the shared stubs code available from the <EM CLASS="A">JNI page (</EM><EM CLASS="URL-Footnote">http://java.sun.com/products/jdk/faq/jnifaq.html</EM>) on the <EM CLASS="CODE">java.sun.com</EM> Web site.</LI></OL></DIV><DIV><H5 CLASS="B"><A NAME="pgfId-1087480"></A><A NAME="94273"></A>Compile the Dynamic or Shared Object Library</H5><P CLASS="Body"><A NAME="pgfId-1087485"></A><A NAME="marker-1087481"></A><A NAME="marker-1087482"></A><A NAME="marker-1087483"></A><A NAME="marker-1087484"></A>The library needs to be compiled as a dynamic or shared object library so it can be loaded at run time. Static or archive libraries are compiled into an executable and cannot be loaded at run time. The shared object or dynamic library for the <EM CLASS="CODE">loadFile</EM> example is compiled on various platforms as follows: </P><DIV><H6 CLASS="D"><A NAME="pgfId-1087486"></A><EM CLASS="D-Code">GNU C/Linux:</EM></H6><PRE CLASS="CODE"><A NAME="pgfId-1087487"></A>gcc -o libnativelib.so -shared -Wl,-soname,libnative.so -I/export/home/jdk1.2/include -I/export/home/jdk1.2/include/linux nativelib.c -static -lc</PRE></DIV><DIV><H6 CLASS="D"><A NAME="pgfId-1087488"></A><EM CLASS="D-Code">SunPro C/Solaris:</EM></H6><PRE CLASS="CODE"><A NAME="pgfId-1087489"></A>cc -G -so libnativelib.so -I/export/home/jdk1.2/include -I/export/home/jdk1.2/include/solaris nativelib.c</PRE></DIV><DIV><H6 CLASS="D"><A NAME="pgfId-1087490"></A>GNU C++/Linux with Xbase:</H6><PRE CLASS="CODE"><A NAME="pgfId-1087491"></A>g++ -o libdbmaplib.so -shared -Wl,-soname,libdbmap.so -I/export/home/jdk1.2/include -I/export/home/jdk1.2/include/linux dbmaplib.cc -static -lc -lxbase</PRE></DIV><DIV><H6 CLASS="D"><A NAME="pgfId-1087492"></A><EM CLASS="D-Code">Win32/WinNT/Win2000:</EM></H6><PRE CLASS="CODE"><A NAME="pgfId-1087493"></A>cl -Ic:/jdk1.2/include -Ic:/jdk1.2/include/win32 -LD nativelib.c -Felibnative.dll</PRE></DIV>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -