author:lanhxg
original site:https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.html
Environment:ubuntu12.04 64bit
ps: 有参考一个哥们的,这个哥们网址忘记了,如有问题可以pm我
Use JNI with C
Step 1: Write a Java Class that uses C Codes - HelloJNI.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class HelloJNI { static { System.loadLibrary("HelloJNI"); // Load native library at runtime // hello.dll (Windows) or libhello.so (Unixes) } // Declare a native method sayHello() that receives nothing and returns void private native void sayHello(); // Test Driver public static void main(String[] args) { new HelloJNI().sayHello(); // invoke the native method } } |
The static initializer invokes System.loadLibrary()
to load the native library "Hello
" (which contains the native methodsayHello()
) during the class loading. It will be mapped to "hello.dll
" in Windows; or"libhello.so
" in Unixes. This library shall be included in Java's library path (kept in Java system variablejava.library.path
); otherwise, the program will throw a UnsatisfiedLinkError
. You could include the library into Java Library's path via VM argument-Djava.library.path=path_to_lib
.
Next, we declare the method sayHello()
as a native instance method, via keywordnative
, which denotes that this method is implemented in another language. A native method does not contain a body. ThesayHello()
is contained in the native library loaded.
The main()
method allocate an instance of HelloJNI
and invoke the native methodsayHello()
.
Compile the "HelloJNI.java
" into "HelloJNI.class
".
> javac HelloJNI.java
Step 2: Create the C/C++ Header file - HelloJNI.h
Run javah
utility on the class file to create a header file for C/C++ programs:
> javah HelloJNI
The output is HelloJNI.h
as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class HelloJNI */ #ifndef _Included_HelloJNI #define _Included_HelloJNI #ifdef __cplusplus extern "C" { #endif/* * Class: HelloJNI * Method: sayHello * Signature: ()V */JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif |
The header declares a C function Java_HelloJNI_sayHello
as follows:
JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *, jobject);
The naming convention for C function is Java_{package_and_classname}_{function_name}(JNI arguments)
. The dot in package name shall be replaced by underscore.
The arguments:
-
JNIEnv*
: reference to JNI environment, which lets you access all the JNI fucntions. -
jobject
: reference to "this
" Java object.
We are not using these arguments in the hello-world example, but will be using them later. Ignore the macrosJNIEXPORT
and JNICALL
for the time being.
The extern "C"
is recognized by C++ compiler only. It notifies the C++ compiler that these functions are to be compiled using C's function naming protocol (instead of C++ naming protocol). C and C++ have different function naming protocols as C++ support function overloading and uses a name mangling scheme to differentiate the overloaded functions. Read "Name Mangling".
Step 3: C Implementation - HelloJNI.c
1 2 3 4 5 6 7 8 9 | #include <jni.h> #include <stdio.h> #include "HelloJNI.h" // Implementation of native method sayHello() of HelloJNI classJNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject thisObj) { printf("Hello World!\n"); return; } |
Save the C program as "HelloJNI.c
".
The header "jni.h
" is available under the "<JAVA_HOME>\include
" and "<JAVA_HOME>\include\win32
" directories, where<JAVA_HOME>
is your JDK installed directory (e.g., "c:\program files\java\jdk1.7.0
").
The C function simply prints the message "Hello world!" to the console.
Compile the C program - this depends on the C compiler you used.
For Ubuntu :
> export export LD_LIBRARY_PATH=$PWD > gcc -I ${JAVA_HOME}/include -I ${JAVA_HOME}/include/linux -fPIC -shared -o libHelloJNI.so HelloJNI.c > java HelloJNI
You can do all steps as a shell:
#!/bin/sh JAVA_HOME=$(readlink -f /usr/bin/javac | sed "s:bin/javac::") #echo $JAVA_HOME export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD echo $LD_LIBRARY_PATH sfile=$1 append=java sh_append=so sh_prefix=lib jfile=${sfile}.${append} cfile=${sfile}.c sharefile=${sh_prefix}${sfile}.${sh_append} javac $jfile javah $sfile gcc -I ${JAVA_HOME}/include -I ${JAVA_HOME}/include/linux -fPIC -shared -o $sharefile $cfile java $sfile
Save above command in a shell file such as "build.sh"
> chmod a+x build.sh > ./build.sh HelloJNI