Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Sprachbeschreibung
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Mathematisches
6 Eigene Klassen schreiben
7 Angewandte Objektorientierung
8 Exceptions
9 Generics, innere Klassen
10 Die Klassenbibliothek
11 Threads und nebenläufige Programmierung
12 Datenstrukturen und Algorithmen
13 Raum und Zeit
14 Dateien und Datenströme
15 Die eXtensible Markup Language (XML)
16 Grafische Oberflächen mit Swing
17 Grafikprogrammierung
18 Netzwerkprogrammierung
19 Verteilte Programmierung mit RMI und Web–Services
20 JavaServer Pages und Servlets
21 Applets
22 Midlets und die Java ME
23 Datenbankmanagement mit JDBC
24 Reflection und Annotationen
25 Logging und Monitoring
26 Sicherheitskonzepte
27 Java Native Interface (JNI)
28 Dienstprogramme für die Java-Umgebung
Stichwort

Download:
- ZIP, ca. 14,1 MB
Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Java ist auch eine Insel (8. Auflage) von Christian Ullenboom
Programmieren mit der Java Standard Edition Version 6
Buch: Java ist auch eine Insel (8. Auflage)

Java ist auch eine Insel (8. Aufl.)
8., aktual. Auflage, geb., mit DVD
1.475 S., 49,90 Euro
Galileo Computing
ISBN 978-3-8362-1371-4
Pfeil 27 Java Native Interface (JNI)
Pfeil 27.1 Java Native Interface und Invocation-API
Pfeil 27.2 Einbinden einer C-Funktion in ein Java-Programm
Pfeil 27.2.1 Schreiben des Java-Codes
Pfeil 27.2.2 Compilieren des Java-Programms
Pfeil 27.2.3 Erzeugen der Header-Datei
Pfeil 27.2.4 Implementierung der Funktion in C
Pfeil 27.2.5 Übersetzen der C-Programme und Erzeugen der dynamischen Bibliothek
Pfeil 27.2.6 Suchort der dynamischen Bibliothek
Pfeil 27.3 Nativ die Stringlänge ermitteln
Pfeil 27.4 Erweiterte JNI-Eigenschaften
Pfeil 27.4.1 Klassendefinitionen
Pfeil 27.4.2 Zugriff auf Attribute
Pfeil 27.5 Einfache Anbindung von existierenden Bibliotheken
Pfeil 27.5.1 C++ Klassen ansprechen
Pfeil 27.5.2 COM-Schnittstellen anzapfen
Pfeil 27.6 Zum Weiterlesen


Galileo Computing - Zum Seitenanfang

27.2 Einbinden einer C-Funktion in ein Java-Programm Zur nächsten ÜberschriftZur vorigen Überschrift

Wir wollen in einem kurzen Überblick sehen, wie die Vorgehensweise prinzipiell ist. Dazu werfen wir einen Blick auf die Implementierung einer einfachen Klasse, die lediglich die Länge der Zeichenkette berechnet.


Galileo Computing - Zum Seitenanfang

27.2.1 Schreiben des Java-Codes Zur nächsten ÜberschriftZur vorigen Überschrift

Zunächst benötigen wir eine Klasse mit einer nativen Funktion. Wir haben gesehen, dass dafür der Modifizierer native nötig ist. Die Funktion besitzt – wie eine abstrakte Methode – keine Implementierung.

public static native int strlen( String s );

Die Funktion soll in eine Klasse mit einem statischen Initialisierungsblock eingebettet werden, der die dynamische Bibliothek lädt:

Listing 27.1 com/tutego/jni/StrLen.java

package com.tutego.jni; 
 
public class StrLen 
{ 
  static { 
    System.loadLibrary( "strlen" ); 
  } 
  public static native int strlen( String s ); 
}

Die Funktion loadLibrary() delegiert an Runtime.getRuntime().loadLibrary(), die wir auch hätten nutzen können.


Hinweis Eine dynamische Bibliothek ist an einen Klassenlader gebunden und wird auch entfernt, wenn die Garbage-Collection den Klassenlader entfernt. Dennoch kann dieselbe aktive Bibliothek nur einmal von der JVM geladen werden. Ein zweiter Versuch wird mit einer UnsatisfiedLinkError bestraft.


Eine Beispielklasse soll lediglich die Funktion aufrufen:

Listing 27.2 com/tutego/jni/StrLenDemo.java

package com.tutego.jni; 
 
public class StrLenDemo 
{ 
  public static void main( String[] args ) 
  { 
    System.out.println( StrLen.strlen("2003 UB313") ); 
  } 
}

Galileo Computing - Zum Seitenanfang

27.2.2 Compilieren des Java-Programms Zur nächsten ÜberschriftZur vorigen Überschrift

Im zweiten Schritt kann der Java-Code übersetzt werden, doch würde eine Ausführung einen Fehler produzieren. Existiert die dynamische Bibliothek nicht oder ist sie nicht im Pfad eingebunden, folgt ein Fehler wie der folgende:

java.lang.UnsatisfiedLinkError: no strlen in java.library.path 
  at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1682) 
  at java.lang.Runtime.loadLibrary0(Runtime.java:822) 
  at java.lang.System.loadLibrary(System.java:992) 
  at com.tutego.jni.StrLen.<clinit>(StrLen.java:7) 
Exception in thread "main"

Galileo Computing - Zum Seitenanfang

27.2.3 Erzeugen der Header-Datei Zur nächsten ÜberschriftZur vorigen Überschrift

Für die nativen Funktionen auf der Java-Seite gibt es auf der C(++)-Seite entsprechende Implementierungen. Die nativ implementierten Funktionen verfügen über eine bestimmte Signatur, damit die JVM bei einem Aufruf an die tatsächliche Implementierung weiterleiten kann.

Die Funktionen in C(++) führt eine Header-Datei auf, die später die Implementierung inkludiert. Die Header-Datei erstellt ein Generator, der aus der Klassendatei die Signatur ausliest und nach einem festen Schema die Funktionen auf der C(++)-Seite benennt. Zum Aufruf des Generators bietet sich ein Ant-Skript an, und auch das JDK bringt mit javah ein Dienstprogramm mit. Mit Ant erstellt der Task <javah> die entsprechende Header-Datei:

Listing 27.3 build.xml, Ausschnitt

<javah classpath="bin" outputFile="strlen.h" verbose="yes"> 
  <class name="com.tutego.jni.StrLen" /> 
</javah>

In diesem Beispiel soll für die Klasse StrLen die Header-Datei strlen.h generiert werden.

Soll das Kommandozeilenprogramm javah benutzt werden, so bestimmt der Schalter -o den Namen der Ausgabedatei:

$ javah -jni -o strlen.h StrLen

An der entstandenen Header-Datei strlen.h sollten keine Änderungen vorgenommen werden. Werfen wir einen Blick hinein, damit wir wissen, welche C-Funktion wir implementieren müssen:

Listing 27.4 strlen.h

/* DO NOT EDIT THIS FILE – it is machine generated */ 
#include <jni.h> 
/* Header for class com_tutego_jni_StrLen */ 
 
#ifndef _Included_com_tutego_jni_StrLen 
#define _Included_com_tutego_jni_StrLen 
#ifdef __cplusplus 
extern "C" { 
#endif 
/* 
 * Class:     com_tutego_jni_StrLen 
 * Method:    strlen 
 * Signature: (Ljava/lang/String;)I 
 */ 
JNIEXPORT jint JNICALL Java_com_tutego_jni_StrLen_strlen 
  (JNIEnv *, jclass, jstring); 
 
#ifdef __cplusplus 
} 
#endif 
#endif

Die Funktion heißt auf der C-Seite nicht einfach strlen(), weil wegen fehlender Namensräume sonst Verwechslungsgefahren mit anderen nativen Methoden anderer Pakete nicht ausgeschlossen sind. Aus diesem Grund enthält der Funktionsname auf der C-Seite den Paketnamen und den Namen der Java-Klasse. Dementsprechend setzt sich der Funktionsname zusammen aus:

  • einem Präfix Java,
  • dem vollständigen Klassenbezeichner, wobei die einzelnen Glieder im Paket durch »_« und nicht durch ».« getrennt sind, und
  • dem Namen der Methode.

Alle primitiven Java-Typen sind auf spezielle Typen in C abgebildet. So steht jint für ein Integer und jstring für einen Pointer auf eine Zeichenkette.


Galileo Computing - Zum Seitenanfang

27.2.4 Implementierung der Funktion in C Zur nächsten ÜberschriftZur vorigen Überschrift

In der automatisch erzeugten Header-Datei lässt sich die Signatur der Funktion ablesen; die Basis für die Implementierung ist:

JNIEXPORT jint JNICALL Java_com_tutego_jni_StrLen_strlen( 
                                    JNIEnv *, jclass, jstring );

Wir erzeugen eine neue Datei strlen.c mit einer Implementierung für Java_com_tutego_ jni_StrLen_strlen(). Dabei soll zunächst etwas auf dem Bildschirm ausgegeben werden; wir wollen damit testen, ob überhaupt alles zusammen läuft. Anschließend kümmern wir uns um die Zeichenkettenlänge.

Listing 27.5 strlen.c

#include <jni.h> 
#include "strlen.h" 
#include <stdio.h> 
JNIEXPORT jint JNICALL Java_com_tutego_jni_StrLen_strlen( 
                            JNIEnv *env, jclass clazz, jstring s ) 
{ 
  printf( "Hallo Java-Freunde!\n" ); 
  return 0; 
}

Der erste Parameter der C-Funktion bekommt so etwas wie eine this-Referenz. Zwar kann jede nicht-statische Methode in Java automatisch this nutzen, doch weiß die Zielsprache C nichts von Objekten und auch nicht, zu welchem Objekt strlen() gehört. Daher übergibt die JVM diese Referenz an die Plattformimplementierung, und die this-Referenz zeigt auf das StrLen-Objekt.


Galileo Computing - Zum Seitenanfang

27.2.5 Übersetzen der C-Programme und Erzeugen der dynamischen Bibliothek Zur nächsten ÜberschriftZur vorigen Überschrift

Der C(++)-Compiler muss nun die dynamische Bibliothek übersetzen. Die dynamisch ladbaren Bibliotheken sind unter Windows die .dll-Dateien (dynamic link libraries ) und unter Unix Dateien mit der Endung .so (shared objects). Die .dll- und .so-Dateien erzeugt prinzipiell jeder Compiler, wobei zu beachten ist, dass jeder Compiler andere Aufrufkonventionen befolgt.

Auf dem Markt gibt es eine Reihe guter und freier Compiler, die für die Übersetzung verwendet werden können:

  • GCC (GNU Compiler Collection) http://gcc.gnu.org/; freier Klassiker für unzählige Plattformen

Die GNU Compiler Collection

Da jeder Compiler andere Aufrufkonventionen hat, führen wir das Beispiel am GCC durch. GCC ist klassischerweise ein Unix-Compiler, doch gibt es ihn auch für Windows. Cygwin ist eine Sammlung von unter Unix bekannten Tools für Windows, und ein Teil davon ist der C(++)-Compiler. Für die Installation wird zunächst unter http://www.cygwin.com/ das kleine Programm setup.exe geladen (es steckt hinter dem Link Install Cygwin now). Im Dialog Choose A Download Source wählen wir Install from Internet, um aus dem Internet alle nötigen Pakete geladen zu bekommen. Im Dialog Select Root Install Directory geben wir zum Beispiel c:\cygwin an. Cygwin speichert die geladenen Teile erst zwischen und möchte dazu auch ein Verzeichnis bekommen – das Verzeichnis kann dann gelöscht werden. Wir geben anschließend eine Download Site an – zum Beispiel aus Deutschland – und wählen dann im nächsten Dialog die zu ladenden Pakete. Uns interessiert aus dem Zweig Devel der gcc-core (bzw. gcc-g++). Die Wahl selektiert automatisch ein paar weitere abgeleitete Pakete. (Den gdb können wir angeben, wenn C-Programme gedebuggt werden sollen.)

Nach der Installation können wir eine Konsole aufmachen und in das Verzeichnis C:\cygwin\bin wechseln. Der Aufruf von gcc ohne Argumente liefert bei erfolgreicher Installation die Fehlermeldung »gcc: no input files«. Wir könnten nun den Suchpfad für den GCC-Compiler anpassen, doch soll ein Ant-Skript die Übersetzung steuern.

Übersetzen mit Ant

Das Build-Tool Ant bringt in der Standard-Distribution keinen Task mit, der einen C-Compiler anstößt. Nichtsdestotrotz lassen sich mit <exec> externe Programme aufrufen. Somit sieht das ganze Build-Skript folgendermaßen aus:

Listing 27.6 build.xml

<project default="cc" basedir="."> 
  <target name="javah"> 
    <javah classpath="bin" outputFile="strlen.h" verbose="yes"> 
      <class name="com.tutego.jni.StrLen" /> 
    </javah> 
  </target> 
  <target name="cc" depends="javah"> 
    <exec dir="c:/cygwin/bin/" executable="c:/cygwin/bin/gcc"> 
      <arg value="-mno-cygwin" /> 
      <arg value="-I" /> 
      <arg value="C:/Programme/Java/jdk1.6.0/include" /> 
      <arg value="-I" /> 
      <arg value="C:/Programme/Java/jdk1.6.0/include/win32" /> 
      <arg value="-shared" /> 
      <arg value="-Wl,--add-stdcall-alias" /> 
      <arg value="-o" /> 
      <arg value="${basedir}/strlen.dll" /> 
      <arg value="${basedir}/strlen.c" /> 
    </exec> 
  </target> 
</project>

Hinweis Die dynamische Bibliothek muss unter Windows die Endung .dll und unter Unix-Systemen die Endung .so haben. In der Unix-Welt beginnen die dynamischen Bibliotheken mit dem Präfix lib, sodass sich daraus für eine Datei die Namensgebung libName.so ergibt.


Wer den <exec>-Task nicht verwenden mag, der kann auch die externen CC-Tasks unter http://ant-contrib.sourceforge.net/ nutzen.


Galileo Computing - Zum Seitenanfang

27.2.6 Suchort der dynamischen Bibliothek topZur vorigen Überschrift

Um bei der Aufforderung mit loadLibrary() die dynamische Bibliothek zu finden, wertet die Laufzeitumgebung die Umgebungsvariable LD_LIBRARY_PATH aus. Diese muss unter Umständen noch gesetzt werden. Befinden wir uns im selben Verzeichnis, ist das nicht nötig.

Welche Pfade die Laufzeitumgebung durchsucht, zeigt die folgende einfache Zeile:

System.out.println( System.getProperty("java.library.path") );

Eine Alternative zu System.loadLibrary(String) ist die Funktion System.load(String). Im Gegensatz zu loadLibrary() erwartet load() einen absoluten Pfad zur Bibliothek.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.






<< zurück
  Zum Katalog
Zum Katalog: Java ist auch eine Insel





Java ist auch eine Insel
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Tipp
Zum Katalog: Coding for Fun





 Coding for Fun


 Buchempfehlungen
Zum Katalog: Objektorientierte Programmierung





 Objektorientierte
 Programmierung


Zum Katalog: Einstieg in Eclipse 3.4






 Einstieg in
 Eclipse 3.4


Zum Katalog: Java 6 lernen mit Eclipse






 Java 6 lernen
 mit Eclipse


Zum Katalog: NetBeans Platform 6






 NetBeans
 Platform 6


Zum Katalog: Java und XML






 Java und XML


Zum Katalog: Visual C# 2008






 Visual C# 2008


Zum Katalog: IT-Handbuch für Fachinformatiker






 IT-Handbuch für
 Fachinformatiker


Zum Katalog: C++ von A bis Z






 C++ von A bis Z


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Galileo Press 2009
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de