La función GetStringUTFChar recupera caracteres de bits desde un jstring de 16 bits usando el Formato de Transformación Unicode (UTF). UTF representa los caracteres Unicode como un string de 8 ó 16 bits sin perder ninguna información. El terpcer parámetro GetStringUTFChar es el resultado JNI_TRUE si se hace una copia olcar de jstring o JNI_FALSE si no se hace.
C Version: (*env)->GetStringUTFChars(env, name, iscopy) C++ Version: env->GetStringUTFChars(name, iscopy)
La siguiente función C de JNI convierte un array de caracteres C en un jstring:
El siguiente ejemplo convierte el array de caracteres C lastfile[80] en un jstring, que es devuelto al método Java que lo llamó:(*env)->NewStringUTF(env, lastfile)
static char lastfile[80];
JNIEXPORT jstring JNICALL Java_ReadFile_lastFile
(JNIEnv *env, jobject jobj) {
return((*env)->NewStringUTF(env, lastfile));
}
Para permitir quela JVM1 conozca como hemos terminado la representación UTF, llamamos a la función de conversión ReleaseStringUTFChars como se muestra abajo. El segundo argumento es el valor del jstring original usado para construir la representación UTF, y el tercer argumento es la referencia a la representación local de ese String.
Si nuestro código nativo puede funcionar con Unicode, sin necesidar de representaciones UTF intermedias, llamamos al función GetStringChars para recuperar el string Unicode, y liberar la referencia con una llamada a ReleaseStringChars:(*env)->ReleaseStringUTFChars(env, name, mfile);
JNIEXPORT jbyteArray JNICALL Java_ReadFile_loadFile
(JNIEnv * env, jobject jobj, jstring name) {
caddr_t m;
jbyteArray jb;
struct stat finfo;
jboolean iscopy;
const jchar *mfile = (*env)->GetStringChars(env,
name, &iscopy);
//...
(*env)->ReleaseStringChars(env, name, mfile);
Por ejemplo, para crear un nuevo array de floats, llamamos a NewFloatArray, o para crear un nuevo array de bytes, llamamos a NewByteArray. Este esquema de nombres se extiende para la recuperación de elementos, para añadir elementos, y para modificar elementos del array. Para obtener un nuevo array de bytes, llamamos a GetByteArrayElements. Para añadir o modificar elementos en el array, llamamos a Set<type>ArrayElements.
La función GetByteArrayElements afecta a todo el array. Para trabajar con un proción del array, llamamos a GetByteArrayRegion. Sólo hay una función Set<type>ArrayRegion para modificar elementos de un array. Sin embargo la región podría tener un tamaño 1, lo que sería equivalente a la no-existente Sete<type>ArrayElements.
| Tipo de Código Nativo |
Funciones usadas |
|---|---|
| jboolean | NewBooleanArray |
| GetBooleanArrayElements | |
| GetBooleanArrayRegion/SetBooleanArrayRegion | |
| ReleaseBooleanArrayRegion | |
| jbyte | NewByteArray |
| GetByteArrayElements | |
| GetByteArrayRegion/SetByteArrayRegion | |
| ReleaseByteArrayRegion | |
| jchar | NewCharArray |
| GetCharArrayElements | |
| GetCharArrayRegion/SetCharArrayRegion | |
| ReleaseCharArrayRegion | |
| jdouble | NewDoubleArray |
| GetDoubleArrayElements | |
| GetDoubleArrayRegion/SetDoubleArrayRegion | |
| ReleaseDoubleArrayRegion | |
| jfloat | NewFloatArray |
| GetFloatArrayElements | |
| GetFloatArrayRegion/SetFloatArrayRegion | |
| ReleaseFloatArrayRegion | |
| jint | NewIntArray |
| GetIntArrayElements | |
| GetIntArrayRegion/SetIntArrayRegion | |
| ReleaseIntArrayRegion | |
| jlong | NewLongArray |
| GetLongArrayElements | |
| GetLongArrayRegion/SetLongArrayRegion | |
| ReleaseLongArrayRegion | |
| jobject | NewObjectArray |
| GetObjectArrayElement/SetObjectArrayElement | |
| jshort | NewShortArray |
| GetShortArrayElements | |
| GetShortArrayRegion/SetShortArrayRegion | |
| ReleaseShortArrayRegion |
En el método nativo loadFile del ejemplo de la sección anterior, se actualiza el array entero especificando una región que tiene el tamño del fichero que está siendo leído:
El array es devuelto al método Java llamandte, que luego, envía al recolector de basura la referencia del array cuando ya no es utilizado. El array puede ser liberado explícitamente con la siguiente llamada:jbyteArray jb; jb=(*env)->NewByteArray(env, finfo.st_size); (*env)->SetByteArrayRegion(env, jb, 0, finfo.st_size, (jbyte *)m); close(fd);
(*env)-> ReleaseByteArrayElements(env, jb,
(jbyte *)m, 0);
El último argumento de la función ReleaseByteArrayElements puede tener los siguientes valores:
En el método nativo loadfile del ejemplo de la página anterior, el array no se liberó explícitamente. Una forma de asegurarnos de que el array es recolectado por el recolector de basura cuando ya no lo necesitamos, es llamar al método Java, pasarle el array de bytes y luego liberar la copia local del array. Esta técnica se muestra en la sección Arrays Multi-Dimensionales.
El siguiente ejemplo C++ muestra cómo llamar a NewObjectArray para crear un array deobjetos String. El tamaño del array se configurará a cinco. la definición de la clase es devuelta desde una llamada a FindClass, y los elementos del array serán inicializados con un cadena vacía. Los elementos del array se actualizarán llamando a SetObjectArrayElement con la posició y el valor a poner en el array.
#include <jni.h>
#include "ArrayHandler.h"
JNIEXPORT jobjectArray JNICALL
Java_ArrayHandler_returnArray
(JNIEnv *env, jobject jobj){
jobjectArray ret;
int i;
char *message[5]= {"first",
"second",
"third",
"fourth",
"fifth"};
ret= (jobjectArray)env->NewObjectArray(5,
env->FindClass("java/lang/String"),
env->NewStringUTF(""));
for(i=0;i<5;i++) {
env->SetObjectArrayElement(
ret,i,env->NewStringUTF(message[i]));
}
return(ret);
}
La clase java que llama a este método nativo es la siguiente:
public class ArrayHandler {
public native String[] returnArray();
static{
System.loadLibrary("nativelib");
}
public static void main(String args[]) {
String ar[];
ArrayHandler ah= new ArrayHandler();
ar = ah.returnArray();
for (int i=0; i<5; i++) {
System.out.println("array element"+i+
"=" + ar[i]);
}
}
}
En el lenguaje java, cualquier array que tenga más de una dimensión es tratado como un array de arrys. Por ejemplo, un array de enteros de dos dimensiones es manejado como un array de arrays de enteros. El array se lee horizontalmente, o también conocido como órden de fila.
Otros lenguajes como FORTRAN usan la ordenación por columnas, por eso es necesario un cuidado extra su nuestro programa maneja un array Java a una función FORTRAN. También, los elementos de un array de una aplicación Java no está garantizado que sean contiguos en la memoria. Algunas librerías usan el conocimiento de que los elementos de un array se almacenan uno junto al otro en la memoria para realizar optimizaciones de velocidad, por eso podríamos necesitar hacer una copia local del array para pasarselo a estas funciones.
El siguiente ejemplo pasad un array de dos dimensiones a un método nativo que extrae los elementos, realiza un cálculo, y llama al método Java para devolver los resultados.
El array es pasado como un objeto array que contiene un array de jints. Los elementos individuales se extraen primero recuperando un ejemplar de jintArray desde el objeto array llamando a GetObjectArrayElement, y luego se extraen los elementos desde la fila jintArray.
El ejemplo usa una matriz de tamaño fijo. Su no conocemos el tamaño del array que se está utilizando, la función GetArrayLength(array) devuelve el tamaño del array más exterior. Necesitaremos llamar a la función GetArrayLength(array) sobre cada dimensión del array para descubrir su tamaño total.
El nuevo array enviado de vuelta al programa Java está construido a la inversa. Primero, se crea un ejemplar de jintArray y este ejemplar se pone en el objeto array llamando a SetObjectArrayElement.
public class ArrayManipulation {
private int arrayResults[][];
Boolean lock=new Boolean(true);
int arraySize=-1;
public native void manipulateArray(
int[][] multiplier, Boolean lock);
static{
System.loadLibrary("nativelib");
}
public void sendArrayResults(int results[][]) {
arraySize=results.length;
arrayResults=new int[results.length][];
System.arraycopy(results,0,arrayResults,
0,arraySize);
}
public void displayArray() {
for (int i=0; i<arraySize; i++) {
for(int j=0; j <arrayResults[i].length;j++) {
System.out.println("array element "+i+","+j+
"= " + arrayResults[i][j]);
}
}
}
public static void main(String args[]) {
int[][] ar = new int[3][3];
int count=3;
for(int i=0;i<3;i++) {
for(int j=0;j<3;j++) {
ar[i][j]=count;
}
count++;
}
ArrayManipulation am= new ArrayManipulation();
am.manipulateArray(ar, am.lock);
am.displayArray();
}
}
#include <jni.h>
#include <iostream.h>
#include "ArrayManipulation.h"
JNIEXPORT void
JNICALL Java_ArrayManipulation_manipulateArray
(JNIEnv *env, jobject jobj, jobjectArray elements,
jobject lock){
jobjectArray ret;
int i,j;
jint arraysize;
int asize;
jclass cls;
jmethodID mid;
jfieldID fid;
long localArrayCopy[3][3];
long localMatrix[3]={4,4,4};
for(i=0; i<3; i++) {
jintArray oneDim=
(jintArray)env->GetObjectArrayElement(
elements, i);
jint *element=env->GetIntArrayElements(oneDim, 0);
for(j=0; j<3; j++) {
localArrayCopy[i][j]= element[j];
}
}
// With the C++ copy of the array,
// process the array with LAPACK, BLAS, etc.
for (i=0;i<3;i++) {
for (j=0; j<3 ; j++) {
localArrayCopy[i][j]=
localArrayCopy[i][j]*localMatrix[i];
}
}
// Create array to send back
jintArray row= (jintArray)env->NewIntArray(3);
ret=(jobjectArray)env->NewObjectArray(
3, env->GetObjectClass(row), 0);
for(i=0;i<3;i++) {
row= (jintArray)env->NewIntArray(3);
env->SetIntArrayRegion((jintArray)row,(
jsize)0,3,(jint *)localArrayCopy[i]);
env->SetObjectArrayElement(ret,i,row);
}
cls=env->GetObjectClass(jobj);
mid=env->GetMethodID(cls, "sendArrayResults",
"([[I)V");
if (mid == 0) {
cout <<"Can't find method sendArrayResults";
return;
}
env->ExceptionClear();
env->MonitorEnter(lock);
env->CallVoidMethod(jobj, mid, ret);
env->MonitorExit(lock);
if(env->ExceptionOccurred()) {
cout << "error occured copying array back" << endl;
env->ExceptionDescribe();
env->ExceptionClear();
}
fid=env->GetFieldID(cls, "arraySize", "I");
if (fid == 0) {
cout <<"Can't find field arraySize";
return;
}
asize=env->GetIntField(jobj,fid);
if(!env->ExceptionOccurred()) {
cout<< "Java array size=" << asize << endl;
} else {
env->ExceptionClear();
}
return;
}
_______
1 Cuando se usan en toda esta site, los términos, "Java virtual machine" o "JVM" significa una máquina virtual de la plataforma Java.