欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

JNI参数传递详细介绍,jni参数详细介绍

来源: javaer 分享于  点击 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
另外,以“L”开头的签名代表Java的类,如"Ljava/lang/String;"就代表一个Java的String类型。以“[”开头的代表数组类型,[I代表一个整型的数组。V代表void类型。方法签名的形式为(参数签名)返回值类型签名例如方法double func(int a, int b)的方法签名为(II)D。

(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



2.传递String类型

 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.


相关文章

    暂无相关文章
相关栏目:

用户点评