1. 创建需要调用本地方法的JAVA源文件,本文以NativeTest类为例,源代码如下:
public class NativeTest {
private native int maxNative(int a, int b);
private native String subStringNative(String str, int begin, int end);
static {
System.loadLibrary("NativeTest");
}
public int max(int a, int b) {
return maxNative(a, b);
}
public String subString(String str, int begin, int end) {
return subStringNative(str, begin, end);
}
public static void main(String[] args) {
NativeTest test = new NativeTest();
System.out.println("result:" + test.max(3, 8));
String str = "Java Native Interface: Programmer's Guide and Specification";
String subStr = test.subString(str, 0, 7);
System.out.println(subStr);
subStr = test.subString(str, 0, 256);
System.out.println(subStr);
// should throw IllegalArgumentException
subStr = test.subString(str, -1, 7);
System.out.println(subStr);
}
}
这个JAVA类有两个本地方法maxNative和substringNative,在以后的C本地代码中将会实现这两个方法。
2. 编译NativeTest.java
$ javac NativeTest.java
3. 利用javah创建本地方法头文件
$ javah -jni NativeTest
生成的NativeTest.h源代码如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class NativeTest */
#ifndef _Included_NativeTest
#define _Included_NativeTest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: NativeTest
* Method: maxNative
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_NativeTest_maxNative
(JNIEnv *, jobject, jint, jint);
/*
* Class: NativeTest
* Method: subStringNative
* Signature: (Ljava/lang/String;II)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_NativeTest_subStringNative
(JNIEnv *, jobject, jstring, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
头文件中声明了两个函数分别对应月上面JAVA类的两个本地方法.
4. 编写NativeTest.c来实现NativeTest.h的函数
#include <jni.h>
#include <string.h>
#include <stdlib.h>
#include "NativeTest.h"
static void ThrowByName(JNIEnv *env, const char *name, const char *msg)
{
jclass cls = (*env)->FindClass(env, name);
if (cls != 0) /* Otherwise an exception has already been thrown */
(*env)->ThrowNew(env, cls, msg);
}
static void ThrowNullPointerException(JNIEnv *env, const char *msg)
{
ThrowByName(env, "java/lang/NullPointerException", msg);
}
static void ThrowIllegalArgumentException(JNIEnv *env, const char *msg)
{
ThrowByName(env, "java/lang/IllegalArgumentException", msg);
}
static void ThrowOutOfMemoryError(JNIEnv *env, const char *msg)
{
ThrowByName(env, "java/lang/OutOfMemoryError", msg);
}
JNIEXPORT jint JNICALL
Java_NativeTest_maxNative(JNIEnv *env, jobject obj, jint a, jint b)
{
return (a > b ? a : b);
}
JNIEXPORT jstring JNICALL
Java_NativeTest_subStringNative(JNIEnv *env, jobject this, jstring str, jint begin, jint end)
{
const jbyte *s;
char *sub;
int total_len, sub_len;
s = (*env)->GetStringUTFChars(env, str, NULL);
if (s == NULL) {
return NULL; /* OutOfMemoryError already thrown */
}
total_len = strlen(s);
if (begin < 0 || begin >= total_len || begin > end) {
(*env)->ReleaseStringUTFChars(env, str, s);
ThrowIllegalArgumentException(env, "Invalid arguments");
return NULL;
}
sub_len = (end >= total_len) ? (total_len-begin) : (end-begin+1);
sub = (char *)malloc(sizeof(char)*(sub_len+1));
if (sub == NULL) {
(*env)->ReleaseStringUTFChars(env, str, s);
ThrowOutOfMemoryError(env, "Can not allocate memory.");
return NULL;
}
strncpy(sub, s+begin, sub_len);
jstring jsub = (*env)->NewStringUTF(env, sub);
(*env)->ReleaseStringUTFChars(env, str, s);
free(sub);
return jsub;
}
5. 编译C源文件并生成动态链接库
$ gcc -fPIC -c -I/usr/local/tools/jdk1.6.0_25/include -I/usr/local/tools/jdk1.6.0_25/include/linux NativeTest.c
$ gcc -shared -o libNativeTest.so NativeTest.o
6. 设置java.library.path运行java程序
$ java -Djava.library.path=. NativeTest
运行结果如下:
result:8
Java Nat
Java Native Interface: Programmer's Guide and Specification
Exception in thread "main" java.lang.IllegalArgumentException: Invalid arguments
at NativeTest.subStringNative(Native Method)
at NativeTest.subString(NativeTest.java:14)
at NativeTest.main(NativeTest.java:29)