19.03 JNI Parameterübergabe

Nachdem Sie bereits ein einfaches JNI Beispiel erstellt und erfolgreich ausgeführt haben, steigen wir in diesem Kapitel ein wenig tiefer in die Materie ein. Wir beschäftigen uns mit Übergabeparameter von Java an eine native Bibliothek und dem Rückgabewert der nativen Bibliothek an Java.

Als Beispiel verwenden wir einen simplen Taschenrechner in Form einer C-Library, dem zwei Ganzzahlen und ein Operator übergeben werden können. Je nach Operator werden die Zahlen addiert, subtrahiert, dividiert oder multipliziert.

Die Java Klasse wird ganz normal mit einer nativen Methode zur Berechnung inkl. der gewünschten Parameter und des Rückgabewerts (einem int als Ergebnis) erzeugt. Zusätzlich definieren wir zu Testzwecken gleich noch eine Main Methode:

package de.jbb.jni;

public class SimpleParameterTest {

  public static void main(String[] args) {

    SimpleParameterTest spt = new SimpleParameterTest();
    System.out.println(spt.calc(10, 5, "+"));
    System.out.println(spt.calc(6, 3, "/"));
    System.out.println(spt.calc(2, 5, "-"));
    System.out.println(spt.calc(7, 6, "*"));
  }

  static {  
    System.loadLibrary("calculator");  
  }  

  public native int calc(int first, int second, String operator);
}

Nachdem Sie die Klasse kompiliert und die dazugehörige Header-Datei (wie im letzten Kapitel beschrieben) mit javah erzeugt haben, können wir uns dem eigentlich interessantem Teil, dem C-Programm widmen. Dabei ist zu beachten, dass Die Datentypen nicht einfach von Java nach C übernommen werden können. Aus einem Java int wird in C ein jint, aus einem boolean ein jboolean. Anbei finden Sie eine Übersicht der jeweiligen Derivate, die direkt weiterverwendet werden können.

„Weiterverwendet“ bedeutet in diesem Fall, dass mit den Typen sofort gearbeitet werden kann, ohne dass sie vorher in irgendeiner Weise konvertiert werden müssen.

Java Native
boolean jboolean
byte jbyte
char jchar
short jshort
int jint
long jlong
float jfloat
double jdouble
void void

Mit diesem Wissen können wir eine C-Library schreiben, die mit unseren beiden Zahlen rechnen kann. Lediglich der String (nativ: jstring) wurde noch nicht berücksichtigt. Deshalb wird der Operator fürs Erste ignoriert. Es soll genügen, wenn am Anfang einfach beide Zahlen addiert werden. Als Rückgabewert wird ebenfalls wieder ein jint verwendet. Dieser wird dann automatisch in einen int konvertiert.

#include <jni.h>
#include "de_jbb_jni_SimpleParameterTest.h"

JNIEXPORT jint JNICALL Java_de_jbb_jni_SimpleParameterTest_calc(
    JNIEnv *env, jobject obj, jint first, jint second, jstring operator) {
  return first + second;
}

Nach der Kompilierung der Library können wir das Programm ausführen. Wir erhalten als Ausgabe:

15
9
7
13

Um den Rechner zu vervollständigen, muss noch der Operator interpretiert werden. Mit der C-Methode strcmp kann man zwei Zeichenketten vergleichen. Bleibt die Frage, wie der jstring in eine C-Zeichenkette (char-Array) umgewandelt werden kann. Hierfür wird eine Funktion der JNI Umgebung (JNIEnv) eingesetzt. Mit dem Aufruf GetStringUTFChars kann ein in Unicode kodierter Java String (16 Bit) in ein UTF-8 C-char-Array (8 Bit) umgewandelt werden.

const char *c_op = (*env)->GetStringUTFChars(env, operator, 0);

Bei Funktionsaufrufen der JNI Umgebung wird in C standardmäßig zuerst die JNI Umgebung selbst übergeben (in C++ kann darauf verzichtet werden). Anschließend folgt hier der zu konvertierende jstring und ein Flag, ob eine Kopie angelegt werden soll oder nicht.

Jetzt können Sie den simplen Taschenrechner vervollständigen:

#include <jni.h>
#include <string.h>
#include "de_jbb_jni_SimpleParameterTest.h"

JNIEXPORT jint JNICALL Java_de_jbb_jni_SimpleParameterTest_calc(JNIEnv *env, jobject obj, jint first, jint second, jstring operator) {
  const char *c_op = (*env)->GetStringUTFChars(env, operator, 0);
  jint ret = 0;
  if (strcmp(c_op, "-") == 0) {
    ret = first - second;
  }
  if (strcmp(c_op, "+") == 0) {
    ret =first + second;
  }
  if (strcmp(c_op, "/") == 0) {
    ret = first / second;
  }
  if (strcmp(c_op, "*") == 0) {
    ret =first * second;
  }
  (*env)->ReleaseStringUTFChars(env, operator, c_op);
  return ret;
}

Ausgabe:

15
2
-3
42

Im nächsten Kapitel werden Sie weitere Funktionen der JNI Umgebung kennenlernen.

Schreibe einen Kommentar

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.