首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

Java Programming Tutorial-JNI(通译)(续二)

2013-07-09 
Java Programming Tutorial-JNI(翻译)(续二)? ? ? ? ? 最近太忙了,对这个JNI programing Tutorial的翻译停

Java Programming Tutorial-JNI(翻译)(续二)

? ? ? ? ? 最近太忙了,对这个JNI programing Tutorial的翻译停止了很长时间,正好赶上周末,把剩下的东西写下来,否则就虎头蛇尾了。

? ? ? ? ? JNI基础

? ? ? ? ? JNI在native系统定义了如下JNI的类型

? ? ? ? ? 1. java原始类型:jnit, jbyte, jshort,jlong,jfloat,jdouble,jchar,jboolean分别对应java中的int,byte,short,long,short,float,double,char 和boolean。

? ? ? ? ? 2. java引用类型:jobject对应java.lang.Object,定义了一下子类型:

? ? ? ? ? ? ? ? ? ? ? ?a. jclass ->java.lang.Class

? ? ? ? ? ? ? ? ? ? ? ?b. jstring->java.lang.String

? ? ? ? ? ? ? ? ? ? ? ?c. jthrowable->java.lang.Throwable

? ? ? ? ? ? ? ? ? ? ? ?d. jarray为java的数组,数组是引用类型可以存放8种原始类型和Object的数据,这8种原始类型的数组分别是:jintArray,jbyteArray,jshortArray,jlongArray,jfloatArray,jdoubleArray,jcharArray和jbooleanArray,还有救是jbojectArray.

? ? ?

? ? ? ? ? native的函数可以接受这些JNI类型的参数并且返回这些类型的值,然而,native的函数只能操作native的数据类型,所以我们需要转换数据类型在native类型和JNI类型之间。转换的工作可能占到JNI代码的绝大多数。

?

? ? ? ? ?传递原始类型数据

? ? ? ? ? Java JNI Program:TestJNIPrimitive.java

? ? ? ? ??

public class TestJNIPrimitive {   static {      System.loadLibrary("myjni"); // myjni.dll (Windows) or libmyjni.so (Unixes)   }   // Native method that receives two ints and return a double containing the average   private native double average(int n1, int n2);    public static void main(String args[]) {      System.out.println("In Java, the average is " + new TestJNIPrimitive().average(3, 2));   }}

?

? ? ? ? ?这个java程序加载了一个共享库myjni.dll(在Windows上)或者libmyjni.so(在Unixes上). 声明了一个native的方法average(),接受两个int类型的参数,并且返回一个double类型的平均值。

? ? ? ? ?编译代码javac TestJNIPrimative.java,生成头文件javah TestJNIPrimitive,主要内容如下:

? ? ? ? ?

JNIEXPORT jdouble JNICALL Java_TestJNIPrimitive_average(JNIEnv *, jobject, jint, jint);

? ?

? ? ? ? ?“jni.h”和"win32\jni_mh.h"包含这8种JNI原始类型和一个jsize的typedef定义描述,如下:

?

? ? ? ? ??

// In "win\jni_mh.h" - machine header which is machine dependenttypedef long            jint;typedef __int64         jlong;typedef signed char     jbyte; // In "jni.h"typedef unsigned char   jboolean;typedef unsigned short  jchar;typedef short           jshort;typedef float           jfloat;typedef double          jdouble;typedef jint            jsize;

? ? ?

? ? ? ? ? ? ?实现的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;}

?

? ? ? ? ? ? 编译:

? ? ? ? ?

gcc -Wl,--add-stdcall-alias -I"<JAVA_HOME>\include" -I"<JAVA_HOME>\include\win32" -shared -o myjni.dll TestJNIPrimitive.c

? ?

? ? ? ? ?传递String类型字符串:

? ? ? ? ??

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);   }}

? ? ? ? 生成的头文件:

? ? ? ?

JNIEXPORT jstring JNICALL Java_TestJNIString_sayHello(JNIEnv *, jobject, jstring);

? ? ? 传递和返回都是jstring类型,传递jstring类型要比传递原始类型要复杂,C的string是一个NULL结尾的字符数组,你需要在java的String类型和C的string类型做一个转换。

? ? ?转换步骤如下:

? ? ? 1. 使用方法char *GetStringUTFChars(JNIEnv*,jstring,jboolean)可以从jstring转换到C的string字符串。

? ? ? 2. NewStringUTF (JNIEnv*,char*)可以生产jstring类型字符串。

? ? ??

#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);}

?

?

? ? ? ? JNI native字符串的API:

? ? ? ? JNI支持Unicode(16位)和UTF-8(1~3字节)的字符串类型,像以null结尾的字符串utf - 8 C字符串(char数组),它应该被用于C / c++程序。

? ? ? ??

// UTF-8 String (encoded to 1-3 byte, backward compatible with 7-bit ASCII)// Can be mapped to null-terminated char-array C-stringconst char * GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy);   // Returns a pointer to an array of bytes representing the string in modified UTF-8 encoding.void ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf);   // Informs the VM that the native code no longer needs access to utf.jstring NewStringUTF(JNIEnv *env, const char *bytes);   // Constructs a new java.lang.String object from an array of characters in modified UTF-8 encoding.jsize GetStringUTFLength(JNIEnv *env, jstring string);   // Returns the length in bytes of the modified UTF-8 representation of a string.void GetStringUTFRegion(JNIEnv *env, jstring str, jsize start, jsize length, char *buf);   // Translates len number of Unicode characters beginning at offset start into modified UTF-8 encoding    // and place the result in the given buffer buf.  // Unicode Strings (16-bit character)const jchar * GetStringChars(JNIEnv *env, jstring string, jboolean *isCopy);   // Returns a pointer to the array of Unicode charactersvoid ReleaseStringChars(JNIEnv *env, jstring string, const jchar *chars);   // Informs the VM that the native code no longer needs access to chars.jstring NewString(JNIEnv *env, const jchar *unicodeChars, jsize length);   // Constructs a new java.lang.String object from an array of Unicode characters.jsize GetStringLength(JNIEnv *env, jstring string);   // Returns the length (the count of Unicode characters) of a Java string.void GetStringRegion(JNIEnv *env, jstring str, jsize start, jsize length, jchar *buf);   // Copies len number of Unicode characters beginning at offset start to the given buffer buf

?

? ??

? ? ? ? ?传递原始类型的数组

? ? ? ? ??

public class TestJNIPrimitiveArray {   static {      System.loadLibrary("myjni"); // myjni.dll (Windows) or libmyjni.so (Unixes)   }   // Native method that receives an int[] and   //  return a double[2] array with [0] as sum and [1] as average   private native double[] sumAndAverage(int[] numbers);    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);

? ? ?现在需要JNI数组和C语言数组中间做一个转换:

? ? ?1. 使用jnit *GetIntArrayElements(JNIEnv *env,jintArray a,jboolean *isCopy),可以得到一个native的jint [].

? ? ?2. 使用jintArray NewIntArray(JNIEnv *env, jsize len),可以生产一个JNI jintArray的对象。

? ? ??

#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;}

? ? ?JNI Array API:

? ? ?

// ArrayType: jintArray, jbyteArray, jshortArray, jlongArray, jfloatArray, jdoubleArray, jcharArray, jbooleanArray// PrimitiveType: int, byte, short, long, float, double, char, boolean// NativeType: jint, jbyte, jshort, jlong, jfloat, jdouble, jchar, jbooleanNativeType * Get<PrimitiveType>ArrayElements(JNIEnv *env, ArrayType array, jboolean *isCopy);void Release<PrimitiveType>ArrayElements(JNIEnv *env, ArrayType array, NativeType *elems, jint mode);void Get<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array, jsize start, jsize length, NativeType *buffer);void Set<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array, jsize start, jsize length, const NativeType *buffer);ArrayType New<PrimitiveType>Array(JNIEnv *env, jsize length);void * GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy);void ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array, void *carray, jint mode);

?

? ? 未完待续。。。。

? ? ? ? ? ??

? ? ? ?

? ? ? ? ?

热点排行