JNI参数传递详细介绍,jni参数详细介绍
分享于 点击 19289 次 点评:254
JNI参数传递详细介绍,jni参数详细介绍
对于Java而言,JNI有很多应用情况,在此就不在赘述。Java和其他语言有不同数据类型,那么本地方法和Java之间是怎样识别Java传递过来的参数和进行数据类型的转换。下面对Java和本地方法之间的参数传递和数据对应进行详细的介绍。
(1)数据映射
Java和C++本地方法的基本数据类型对应关系表。
Native类型 | Java类型 | 描述 | 签名类型 |
---|---|---|---|
unsigned char | jboolean | unsigned 8 bits | Z |
signed char | jbyte | signed 8 bits | B |
unsigned short | jchar | unsigned 16 bits | C |
short | jshort | signed 16 bits | S |
long | jint | signed 32 bits | I |
long long __int64 |
jlong | signed 64 bits | J |
float | jfloat | 32 bits | F |
double | jdouble | 64 bits | D |
void | V |
(2)Java与本地方法的参数传递
1.基本数据类型传递
基本数据类型的传递很简单,根据(1)中的对照表即可。下面给出一个例子。
Java程序如下:
TestJNIPrimitive.java
public class TestJNIPrimitive { static { System.loadLibrary("myjni"); // myjni.dll (Windows) or libmyjni.so (Unixes) } // Declare a native method average() that receives two ints and return a double containing the average private native double average(int n1, int n2); // Test Driver public static void main(String args[]) { System.out.println("In Java, the average is " + new TestJNIPrimitive().average(3, 2)); } }
编译Java程序生成"TestJNIPrimitive.class
" 然后生成C/C++ 头文件 "TestJNIPrimitive.h
":
> javac TestJNIPrimitive.java
> javah TestJNIPrimitive // Output is TestJNIPrimitive.h
在头文件
TestJNIPrimitive.h
中会生成本地方法的声明如下:
JNIEXPORT jdouble JNICALL Java_TestJNIPrimitive_average(JNIEnv *, jobject, jint, jint);
JNIEnv是访问JNI环境的接口,传递复杂的参数会用到,jobjcet代表当前的Java对象,就是调用本地方法的对象。jint和jdouble分别对应Java中的double和int类型。
与之对应的C程序如下 TestJNIPrimitive.c
#include <jni.h>
#include <stdio.h>
#include "TestJNIPrimitive.h"
JNIEXPORT jdouble JNICALL Java_TestJNIPrimitive_average
(JNIEnv *env, jobject thisObj, jint n1, jint n2) {
jdouble result;
printf("In C, the numbers are %d and %d\n", n1, n2);
result = ((jdouble)n1 + n2) / 2.0;
// jint is mapped to int, jdouble is mapped to double
return result;
}
编译c程序为动态库
// MinGW GCC under Windows > set JAVA_HOME={jdk-installed-directory} > gcc -Wl,--add-stdcall-alias -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" -shared -o myjni.dll TestJNIPrimitive.c执行
> java TestJNIPrimitive
TestJNIString.java
public class TestJNIString { static { System.loadLibrary("myjni"); // myjni.dll (Windows) or libmyjni.so (Unixes) } // Native method that receives a Java String and return a Java String private native String sayHello(String msg); public static void main(String args[]) { String result = new TestJNIString().sayHello("Hello from Java"); System.out.println("In Java, the returned string is: " + result); } }
生成.class文件和.h文件
> javac TestJNIString.java > javah TestJNIString在头文件
TestJNIString.h
中会生成本地方法的声明如下:JNIEXPORT jstring JNICALL Java_TestJNIString_sayHello(JNIEnv *, jobject, jstring);
与之对应的C程序如下#include <jni.h> #include <stdio.h> #include "TestJNIString.h" JNIEXPORT jstring JNICALL Java_TestJNIString_sayHello(JNIEnv *env, jobject thisObj, jstring inJNIStr) { // Step 1: Convert the JNI String (jstring) into C-String (char*) const char *inCStr = (*env)->GetStringUTFChars(env, inJNIStr, NULL); if (NULL == inCSt) return NULL; // Step 2: Perform its intended operations printf("In C, the received string is: %s\n", inCStr); (*env)->ReleaseStringUTFChars(env, inJNIStr, inCStr); // release resources // Prompt user for a C-string char outCStr[128]; printf("Enter a String: "); scanf("%s", outCStr); // not more than 127 characters // Step 3: Convert the C-string (char*) into JNI String (jstring) and return return (*env)->NewStringUTF(env, outCStr); }
编译和执行就不讲了
3.传递数组
Java程序TestJNIPrimitiveArray.java
public class TestJNIPrimitiveArray { static { System.loadLibrary("myjni"); // myjni.dll (Windows) or libmyjni.so (Unixes) } // Declare a native method sumAndAverage() that receives an int[] and // return a double[2] array with [0] as sum and [1] as average private native double[] sumAndAverage(int[] numbers); // Test Driver public static void main(String args[]) { int[] numbers = {22, 33, 33}; double[] results = new TestJNIPrimitiveArray().sumAndAverage(numbers); System.out.println("In Java, the sum is " + results[0]); System.out.println("In Java, the average is " + results[1]); } }
编译得到的方法声明
JNIEXPORT jdoubleArray JNICALL Java_TestJNIPrimitiveArray_average (JNIEnv *, jobject, jintArray);
c程序
"TestJNIPrimitiveArray.c
"
#include <jni.h> #include <stdio.h> #include "TestJNIPrimitiveArray.h" JNIEXPORT jdoubleArray JNICALL Java_TestJNIPrimitiveArray_sumAndAverage (JNIEnv *env, jobject thisObj, jintArray inJNIArray) { // Step 1: Convert the incoming JNI jintarray to C's jint[] jint *inCArray = (*env)->GetIntArrayElements(env, inJNIArray, NULL); if (NULL == inCArray) return NULL; jsize length = (*env)->GetArrayLength(env, inJNIArray); // Step 2: Perform its intended operations jint sum = 0; int i; for (i = 0; i < length; i++) { sum += inCArray[i]; } jdouble average = (jdouble)sum / length; (*env)->ReleaseIntArrayElements(env, inJNIArray, inCArray, 0); // release resources jdouble outCArray[] = {sum, average}; // Step 3: Convert the C's Native jdouble[] to JNI jdoublearray, and return jdoubleArray outJNIArray = (*env)->NewDoubleArray(env, 2); // allocate if (NULL == outJNIArray) return NULL; (*env)->SetDoubleArrayRegion(env, outJNIArray, 0 , 2, outCArray); // copy return outJNIArray; }
本文中一些步骤相同就省略了,毕竟本文只是为了说明Java和本地方法的参数传递。
参考:
https://en.wikipedia.org/wiki/Java_Native_Interface
http://notes.maxwi.com/2017/04/20/java-jni-cpp-passing-arguments/
https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.html#zz-4.
相关文章
- 暂无相关文章
用户点评