在此講述使用JNI在Java與C/C++中傳遞參數的方式,並以簡單的例子做示範。
- Accessing Strings
- (Example)
Prompt.java:
contains a native method that prints a string, waits for user input, and then returns the line that the user has typed in.
Prompt.java
class Prompt {
// native method that prints a prompt and reads a line
private native String getLine(String prompt);
public static void main(String args[]) {
Prompt p = new Prompt();
String input = p.getLine("Type a line: ");
System.out.println("User typed: " + input);
}
static {
System.loadLibrary("Prompt");
}
}
- Generate C/C++ header file by "javah -jni CLASS_NAME (Prompt)"
Prompt.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Prompt */
#ifndef _Included_Prompt
#define _Included_Prompt
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Prompt
* Method: getLine
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_Prompt_getLine
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
The name of the C function is formed by concatenating the "Java_" prefix, the "CLASS_NAME", and the "METHOD_NAME". Parameters of Java_Prompt_getLine():
- JNIEnv *: The first parameter, the JNIEnv interface pointer, points to a location that contains a pointer to a function table. A JNI interface pointer (JNIEnv*) is passed as an argument for each native function mapped to a Java method, allowing for interaction with the JNI environment within the native method.(from Wiki)
- jobject: The second argument differs depending on whether the native method is a static or an instance method.
- The second argument to an instance native method is a reference to the object on which the method is invoked, similar to the "this" pointer in C++.
- The second argument to a static native method is a reference to the class in which the method is defined.
- Implementation of Prompt.c
- Native method code must use the appropriate JNI functions to convert jstring objects to C/C++ strings.
(version 1 for JDK1.1)Prompt.c
#include <stdio.h>
#include <jni.h>
#include "Prompt.h"
JNIEXPORT jstring JNICALL
Java_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)
{
char buf[128];
const jbyte *str;
str = (*env)->GetStringUTFChars(env, prompt, NULL);
if (str == NULL) {
return NULL; /* OutOfMemoryError already thrown */
}
printf("%s", str);
(*env)->ReleaseStringUTFChars(env, prompt, str);
/* We assume here that the user does not type more than
* 127 characters */
scanf("%s", buf);
return (*env)->NewStringUTF(env, buf);
}
- GetStringUTFChars: through the JNIEnv interface pointer to read the contents of the string, and converts the jstring reference from Unicode(JAVA) to UTF-8(C/C++).
- Do not forget to check the return value of GetStringUTFChars.
- A chance to fail memory allocation: Because the JVM implementation needs to allocate memory to hold the UTF-8 string. When it happens, GetStringUTFChars returns NULL and throws an OutOfMemoryError exception.
- ReleaseStringUTFChars: When no longer needs the UTF-8 string returned by GetStringUTFChars; Free the memory taken by the UTF-8 string.
New JNI String Functions in Java 2 SDK Release 1.2
(version 2 for JDK1.2)Prompt2.c
#include <stdio.h>
#include <jni.h>
#include "Prompt.h"
JNIEXPORT jstring JNICALL
Java_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)
{
/* assume the prompt string and user input has less than 128
characters */
char outbuf[128], inbuf[128];
int len = (*env)->GetStringLength(env, prompt);
(*env)->GetStringUTFRegion(env, prompt, 0, len, outbuf);
printf("%s", outbuf);
scanf("%s", inbuf);
return (*env)->NewStringUTF(env, inbuf);
}
- GetStringUTFRegion: Copies the content of a string to or from a pre-allocated C buffer in the UTF-8 format. It performs no memory allocation, we need not check for possible out-of-memory conditions.
(The above code, however, lacks the necessary checks to ensure that the prompt string contains less than 128 characters.)
Summary of JNI String Functions
Choosing among JNI String Functions
Accessing Arrays
The JNI treats primitive arrays and object arrays differently.
- Primitive arrays: Primitive arrays contain elements that are of primitive types such as int and boolean. ex. int[ ] iarr; float[ ] farr;
- Object arrays: Object arrays contain elements that are of reference types such as class instances and other arrays. ex. Object[ ] oarr; int[ ][ ] arr2;
- (Example) IntArray.java: calls a native method sumArray that adds up the contents of an int array.
IntArray.java
class IntArray {
private native int sumArray(int[] arr);
public static void main(String[] args) {
IntArray p = new IntArray();
int arr[] = new int[10];
for (int i = 0; i < 10; i++) {
arr[i] = i;
}
int sum = p.sumArray(arr);
System.out.println("sum = " + sum);
}
static {
System.loadLibrary("IntArray");
}
}
- Generate C/C++ header file by "javah -jni CLASS_NAME (IntArray)"
IntArray.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class IntArray */
#ifndef _Included_IntArray
#define _Included_IntArray
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: IntArray
* Method: sumArray
* Signature: ([I)I
*/
JNIEXPORT jint JNICALL Java_IntArray_sumArray
(JNIEnv *, jobject, jintArray);
#ifdef __cplusplus
}
#endif
#endif
- Implementation of IntArray.c
version 1 using GetIntArrayRegion() - IntArray.c
#include <jni.h>
#include "IntArray.h"
JNIEXPORT jint JNICALL
Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr)
{
jint buf[10];
jint i, sum = 0;
(*env)->GetIntArrayRegion(env, arr, 0, 10, buf);
for (i = 0; i < 10; i++) {
sum += buf[i];
}
return sum;
}
- GetIntArrayRegion: to copy all the elements in the integer array into a C buffer (pre-allocated buf).
- The third argument is the starting index of the elements.
- The fourth argument is the number of elements to be copied.
version 2 using GetIntArrayElements() - IntArray2.c
#include <jni.h>
#include "IntArray.h"
JNIEXPORT jint JNICALL
Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr)
{
jint *carr;
jint i, sum = 0;
carr = (*env)->GetIntArrayElements(env, arr, NULL);
if (carr == NULL) {
return 0; /* exception occurred */
}
for (i=0; i<10; i++) {
sum += carr[i];
}
(*env)->ReleaseIntArrayElements(env, arr, carr, 0);
return sum;
}
- The JNI supports a family of Get/Release<type>ArrayElements functions that allow the native code to obtain a direct pointer to the elements of primitive arrays. Because the underlying garbage collector may not support pinning, the virtual machine may return a pointer to a copy of the original primitive array.
Summary of JNI Primitive Array Functions
Choosing among JNI Primitive Array Functions
0 意見:
張貼留言