Paketkonzept von Java Pakete als Strukturierungsmittel Anlegen von Paketen Export von Paketinhalten - public versus nicht-public Import von Paketelementen - explizit / implizit Pakete und Filestruktur Bedeutung von public, (package), private, protected Design-Prinzipien für Paketstrukturen Programmieren 2 - H.Neuendorf (52) Einordnung in Strukturierungsebenen Service / App Modul Unit of deployment & management Paket Klasse jar Unit of state Unit of composition & test ?? Java Programmieren 2 - H.Neuendorf (53) Pakete - Packages Bislang Strukturierung durch Klassen + Methoden Zu feingranular Paket ⇒ Gröberer Strukturierungsmechanismus : : Logische + Physische Zusammenfassung in größerer Einheit = Sammlung zusammengehöriger Klassen + Interfaces JDK besteht aus zahlreichen Paketen – speziell : java.lang : Standardpaket mit erforderlichen Klassen ( String, Math ...) Nur dieses wird in jedes java-File automatisch importiert ! Arbeiten mit Paketen 1. Anlegen eigener Pakete Schlüsselwort : package 2. Einbinden von Paketen Schlüsselwort : import Jedes Paket sollte genau definierte Zuständigkeiten + Aufgaben besitzen ! Paket Klasse1 KlasseN Methoden Attribute Methoden Attribute Programmieren 2 - H.Neuendorf (54) Anlegen von Paketen Am Anfang der Quelldatei (1.Anweisung!) : ⇒ package packageName ; Alle Klassen / IFs dieser Datei gehören dann zu diesem einen Paket Paket = logische Einheit - Klassen können physisch über verschiedene Dateien verteilt sein package graphics; package graphics; class Circle { class Rectangle { … … } } Datei Rectangle.java Datei Circle.java Paket graphics Circle Rectangle Eindeutige Paketnamen via umgekehrter Domain : Ohne package-Angabe gehören alle Klassen + IF der Datei zum namenlosem Standardpaket. Werden im aktuellen Arbeitsverzeichnis gesucht. package de.dhbw-mosbach.graphics ; Programmieren 2 - H.Neuendorf (55) Paket = Sichtbarkeitsgrenze Alles, was zum Paket gehört, ist außerhalb Paket defaultmäßig nicht zugreifbar ! Paketkonzept leistet : Deklaration öffentlicher Schnittstellen Einschränkung von Verwendungen Durchsetzung Geheimnisprinzip Dokumentation Verwendungen im Code Veröffentlichung nur durch expliziten Export ! ⇒ Klassen haben nur Zugriff auf andere IFs / Klassen des gleichen Pakets ! Paketcode kann intern kooperieren - ohne dass Fremdpaket darauf Zugriff hat ! ⇒ Klassen eines Pakets haben keinen Zugriff auf Klassen eines anderen Pakets ! Paket = Namensraum : Innerhalb Paket nur eindeutige Klassen-/ IF-Namen zulässig package yourPack ; package myPack ; class C1 { int x; void m( ){...} } class C1 { int x; class C2 { int y; void m( ) {...} } class C22 { void m( ){...} } // Klassen C1 und C2 sind lokal zu Paket myPack C2 c = new C2( ) ; // Fehler !! // können sich gegenseitig benutzen // Klasse C2 hier unbekannt !! // aber nicht von Außen (= aus anderen Paketen) ansprechbar ! } Programmieren 2 - H.Neuendorf (56) Export von Paket-Inhalten - public Gewährung Zugriff auf Interfaces, Klassen, Methoden, Attribute von Paketen Export von Paketbestandteilen durch public -Deklaration : "Was public ist / exportiert wird, bestimmt Paket selbst !" Voraussetzung für Sichtbarkeit : Zugehörige Klasse / IF selbst auch public deklariert ! Nur public Konstruktoren sind aus Fremdpaketen aufrufbar ! package myPack ; // Auch Paket hat eine Schnittstelle !! Wenn Klasse nur nicht-public Konstruktoren hat, dann kann sie aus anderen Paketen nicht instanziiert werden Zugriff aus Fremd-Paketen : public-Elemente von C1 public class C1 { // C1 wird exportiert public int x ; // Attribut x exportiert int y ; public void m1( ){...} // Methode m1( ) exportiert void m2( ) {...} public C1( int a ) { ... } // dieser Konstruktor exportiert C1( ) {...} } class C2 { … } // C2 von Außen nicht sichtbar ! Nicht-public-Elemente von C1 und Klasse C2 jedoch verborgen ! Erlaubt: C1 obj = new C1( 4 ) ; Verboten: C1 obj = new C1( ) ; Nicht-public-Elemente sind nicht Teil des Vertrags – somit nicht als stabil garantiert Programmieren 2 - H.Neuendorf (57) Verwendung Paket-Inhalte : Import in andere Pakete Voraussetzung für Verwendung exportierter Komponenten in anderen Paketen : Ausdrücklicher Import in verwendenden Paketen " Was von Außen importiert wird, bestimmt das verwendende Paket selbst ! " Sinn : Klare Festlegung, welche fremden Klassen in eigenem Paket verwendet werden ! 1. Volle Paket-Qualifikation des Klassennamens Impliziter Import 2. Import-Anweisung in Quellcode-Datei Expliziter Import package myPack ; package newPack ; public class C1 { … } class C2 { … } package ourPack ; public class C1 { … } // Impliziter Import : class C10 { myPack.C1 obj_1 = new myPack.C1( ) ; ourPack.C1 obj_2 = new ourPack.C1( ) ; // … } Gleichnamige Klassen aus verschiedenen Paketen durch Qualifikation gemeinsam verwendbar Eigene Klassen dürfen so heißen, wie implzit importierte Klassen class C2 { … } Programmieren 2 - H.Neuendorf (58) Expliziter Import Import-Zeile in Quellcode-Datei - Varianten : 1. Import einer einzelnen Klasse : import paketname.klassenname ; 2. Import aller Klassen eines Pakets : import paketname.* ; 3. Statischer Import statischer Elemente einer bestimmten Klasse : import static java.lang.Math.* ; Regeln : import definiert Suchpfad. Import-Anweisungen in Quellcode-Datei direkt nach package-Anweisung ! Bindet kein Coding ein, macht Bytecode nicht länger Import-Anweisungen gelten nur für importierende Quell-Datei ! Kein Linking in Java Alle Klassen müssen verschiedene Namen haben ! Verwendung * ohne Nachteile Eigene Klassen dürfen nicht so heißen, wie explzit importierte Klassen ! → Namenskonflikt ⇒ Impliziter Import In Coding Klassennamen ohne Paket-Qualifikation verwendbar package myPack ; public class C1 { … } class C2 { … } package newPack ; import myPack.C1 ; // expliziter Import class C10 { C1 obj_1 = new C1( ) ; } Programmieren 2 - H.Neuendorf (59) Pakete + Verzeichnisse - Regeln Abbildung : Klassen → Dateien + Pakete → Verzeichnisse 1. Eine public Klasse C muss in Datei namens C.java implementiert werden ! 2. Alle Klassendateien eines Pakets P müssen in einem Verzeichnis namens P liegen ! 3. Eine Datei darf beliebig viele Klassen enthalten, aber nur eine davon darf public sein ! ● Name der public-Klasse C bestimmt Dateinamen: C.java ● Nicht-public-Klassen von public-Klasse intern verwendbar - aber nicht exponiert ● Innere Klassen können public sein und separat importiert werden Paket P mit public Klassen A, B und C ⇒ Verzeichnis P mit Dateien A.java P A B.java C.java P B C A.java set CLASSPATH=… B.java für .jar .zip .class C.java Programmieren 2 - H.Neuendorf (60) Pakete + Verzeichnisse – Schachtelung Paket-Hierachie = Paket aus Paketen Paket P3 ← Paket P1 + Paket P2 Verzeichnis P3 enthält Unterverzeichnisse P1 + P2 mit deren .java-Dateien Keine automatische Sichtbarkeit zwischen inneren + äußeren Paketen ! Benutzung → Angabe gesamter Paketpfad bis zu referenzierten Klassen : import P3.P2.C ; import P3.P2.* ; import P3.* ; // Import aller Klassen direkt aus P3 - nicht aber der Klassen aus P2 und P1 ! P3 P1 B.java P2 A.java C.java N.java D.java Programmieren 2 - H.Neuendorf (61) Pakete + Verzeichnisse in Eclipse Jede Klasse ist einem Package zugeordnet Default ist das default package = namenloses Standardpaket Package anlegen : Eclipse legt pro Package Ordner mit Klassen an : Einbinden IO in Eclipse ohne physische Kopie : 1. IO.class als ZIP- oder JAR-File zentral ablegen 2. Menü Project → Properties → Java Buid Path 3. Tab Libraries wählen 4. Button Add External JARs … 5. Auf IO-ZIP- / -JAR-File verweisen 6. OK Referenz nachträglich entfernbar oder änderbar Programmieren 2 - H.Neuendorf (63) Zugriffsrechte public protected package private public In allen Klassen des eigenen Pakets In allen anderen Paketen, die die Klasse importieren protected In Fremdklassen des selben Pakets - und deren Objekten In Unterklassen der Klasse des selben Pakets – und deren Objekten In Unterklassen der Klasse in anderen Paketen - jedoch nicht auf deren Objekten ! "package" keine Angabe In allen Klassen des eigenen Pakets - aber nicht in anderen Paketen private Nur in eigener Klasse selbst - nirgendwo sonst Zugriff durch Klasse mit Element: Klasse Unterklasse FremdKlasse FremdPackage private X package X X X protected X X X X U-Klasse public X X X X Programmieren 2 - H.Neuendorf (64) Zugriffsrecht protected : Paket P1 Mit Java-Paketkonzept verbunden Paket P2 Oberklasse O : protected void m( ) und deren Unterkl. Unterklasse U2 import P1.* ; Unterklasse1 Fremdklasse1 Fremdklasse2 "Fast alle" haben Zugriff auf die protected-Methode m( ) der Oberklasse P1.O Nur die nicht erbende Fremdklasse2 hat keinen Zugriff auf protected-Elemente der Oberklasse O aus P1 C++ : Durch protected werden erbende Unterklassen gegenüber nicht erbenden Klassen generell privilegiert Java : Paket stellt protected-Komponenten anderen Paketen zur Nutzung innerhalb deren Unterklassen z.Vfg. Programmieren 2 - H.Neuendorf (65) Zugriffsrecht protected Situation für Unterklasse U2 aus anderem Paket P2 Zugriff auf m() nur im Coding der Unterklasse U2 - Nicht auf deren Objekten : package P2 ; U2 u = new U2( ) ; import P1.O ; u.m( ) ; // Fehler !! class U2 extends O { public void test( ) { m( ) ; } // ok! } Gilt auch für geerbte protected static Attribute + Methoden : Außerhalb der Unterklasse U2 auch auf Klassennamen nicht sichtbar ! U2.statischeMethode( ) ; // Fehler !! Denksport : protected = geschützt … …vor direktem Zugriff aus fremden Paketen Oberklasse hat nur einen public / private / protected Konstruktor. Wer kann von ihr erben ? … Programmieren 2 - H.Neuendorf (66) Zusammenspiel Pakete + Interfaces : Verbergen von Konkretisierungen Facade-Pattern : Nur Schnittstellentyp direkt sichtbar - nicht konkreter Implementierungstyp package Facade ; package Other ; public interface IData { int getData( ) ; } import Facade.* ; public class User { package Facade ; public static void main( String[ ] args ) { public abstract class DataFactory { // Naming + Factory : IData d = DataFactory.newIData( "One" ) ; public static IData newIData( String n ) { int n = d.getData( ) ; // ok ! switch( n ) { case "One" : return new DataProvider1( ) ; // Fehler - extern nicht sichtbar : case "Two" : return new DataProvider2( ) ; default : d = new DataProvider1( ) ; return null ; DataProvider d2 = … ; }} } Zugriff auf m() jedoch nur im Coding der Unterklasse 2 : aufImplementierungen deren Objekten : von Außen nicht sichtbar : //Nicht Konkrete } } class DataProvider1 implements IData { public int getData( ) { return 100 ; } } class DataProvider2 implements IData { public int getData( ) { return 200 ; } } Programmieren 2 - H.Neuendorf (67) Zusammenspiel Pakete + Interfaces : Verbergen von Konkretisierungen Design-Idee → minimale Kopplung - maximale Flexibilität : OCP ! Factory liefert konkrete Implementierung - jedoch nur über Interface-Typ ansprechbar Factory liefert Referenz auf Interface-Typ Nur gegen diesen Typ programmiert der Verwender Konkrete Implememtierungs-Typen (Klassen) bleiben paketintern (transparent) ⇒ Jederzeit austauschbar durch andere Implementierungen (Klassen - z.B. DataProviderXY) ⇒ Verwender nicht an bestimmte implementierende Klasse gekoppelt Völlige Entkopplung von Schnittstelle und Implementierung Umsetzung Information Hiding + Zugangskontrolle auf Paketebene ! Public-Elemente des Pakets sind nur Interfaces und Factories, die Zugang zur eigentlichen Implementierung vermitteln. Implementierungsklassen sind nicht öffentlich und nicht importierbar Programmieren 2 - H.Neuendorf (68) Modifizierer von Klassen, Attributen, Methoden Nicht alle Modifizierer auf alles anwendbar : Modifizierer public Klasse Attribut Methode Konstruktor Speziell IFs : X X X protected X X X private X X X X X X X static X (IF) (X innere) final X abstract X (IF) X strictfp X native X IF-Methoden müssen stets public sein IF-Attribute müssen stets public + static + final sein Sind es automatisch - auch wenn nicht explizit vermerkt IF selbst ist jedoch nicht automatisch als Ganzes public ! … Bei public- Paketklassen gilt noch viel schärfer als bei paket-internen nicht-public-Klassen : Keine public-Attribute - sondern nur public-Zugriffsmethoden (Setter / Getter) ⇒ Nur dadurch bewahrt man die Flexibilität, die innere Datenrepräsentation der Klasse später noch verändern / anpassen zu können … Programmieren 2 - H.Neuendorf (69) Package Design Principles Gute Struktur – keine Zyklen ! Problematische Struktur – Zyklen ! Änderung an zB MyDialogs beeinflusst nur die Pakete MyTasks und MyApplikation – nur dort muss entschieden werden, ob neue Version von MyDialogs verwendet wird. Klasse in MyDialogs benutzt nun Klassen aus MyApplikation. Zum Compilieren & Testen von MyDialogs ist nur Paket Windows erforderlich. Zum Compilieren & Testen von MyTasks ist Verfügbarkeit des gesamten Systems erforderlich. Compilieren + Testen des Gesamtsystems kann bottom up erfolgen – im Grunde ein Paket nach dem anderen. System praktisch nur noch als Ganzes testbar + compilierbar Fazit : Klar, einfach, übersichtlich ! Compilationszeiten wachsen stark an. Jeder Entwickler muss mit selben Releasestand aller anderen arbeiten – hoher Koordinationsaufwand. Tool zur Struktur-Analyse : JarAnalyzer Autor: Kirk Knoernschild Testen von MyDialogs setzt Zugriff auf alle Pakete des System voraus! Paket MyTasks ist nun von allen Paketen im System abhängig. Aus einzelnen Paketen ist quasi ein Riesenpaket geworden, dessen Teile nicht mehr isolierbar sind. Fazit : Unübersichtlich, unflexibel, kaum handlebar ! ⇒ Zyklus muss aufgebrochen werden ! Programmieren 2 - H.Neuendorf (70) Package Design Principles Aufbrechen des Zyklus : Anlegen eines neuen Pakets, von dem MyDialogs und MyApplication nun abhängen. Klassen, durch die die beiden Pakete zuvor direkt verbunden wurden, kommen ins neue Paket. Konsequenz : Paketstrukturen müssen an neue Design-Anforderungen angepasst werden. Wachsen des Systems + seiner Logik bedingt auch Wachsen + Wandeln der Paketstruktur. Paketstruktur somit nicht für allemal top down fixierbar - falls Wandelbarkeit, Testbarkeit, Erstellbarkeit des Systems nicht leiden sollen. Weitere Definition von Stabilität : Etwas, das nur mit großer Mühe zu verändern ist – und sich auch deshalb kaum ändert … Stable-Dependencies Principles : Depend in the direction of stability Unterscheiden zwischen Paketen, die sich oft ändern werden, sollen, dürfen bzw. leicht änderbar sind – und solchen Paketen, die sich nicht oft ändern werden, sollen, dürfen - bzw. nur mühsam ändern lassen. Faktoren: Größe, Komplexität, Sicherheitsrelevanz … … insbesondere aber: Zahl der Pakete, die davon abhängen – dh Verantwortlichkeit des Pakets. Leicht veränderliche Pakete sollen von stabilen, schwer veränderlichen Paketen abhängen – nicht umgekehrt ! … sonst würde das leicht veränderliche Paket nicht länger leicht veränderbar sein ! Bsp: Paket Windows sollte sehr stabil sein Paket MyApplication darf sich oft ändern. Programmieren 2 - H.Neuendorf (71) Dokumentation + weitere Tools Dokumentation von Schnittstellen - Tool javadoc DK-Annotationen javadoc + jar mit Eclipse-Unterstützung Weitere JDK-Tools aus bin-Ordner Schematischer Aufbau java.lang / Java SE / Java EE / Java ME Programmieren 2 - H.Neuendorf (72) Dokumentation von Schnittstellen Interfaces, Klassen, Methoden, Attribute JDK-Unterstützung → Tool : Aufruf auf Kommandozeile : ⇒ → Spezifikation Funktionalität + Bedeutung javadoc *.java javadoc [options] {filename | packageName} HTML-Files mit Schnittstellendarstellung + Kommentaren aus Quellcode HTML direkt in DK-Text verwendbar /** ... */ Regeln für Dockommentare (DK) : 1. Jeder DK beschreibt Bezeichner dessen Deklaration unmittelbar folgt 2. Der erste Satz des DK ist Zusammenfassung = Text bis erster Punkt mit Leerschritt 3. * -Zeichen am Anfang von DK-Zeilen werden ignoriert 4. Nur DKs direkt vor Interfaces, Klassen, Methoden und Attributen werden verarbeitet 5. Wenn geerbte Methode (zB aus Interface !) keinen eigenen DK in Unterklasse hat, erbt sie DK des Obertyps … Programmieren 2 - H.Neuendorf (73) Dokumentation : DK-Annotationen @ Java-Doc-Tags : /** ... */ (u.a.) @param Spezikation einzelner Parameter. Erstes Wort Parametername, Rest Beschreibung @return Rückgabewert der Methode @author Autorenangabe @version Versionsangabe http://download.oracle.com/javase/8/docs/technotes/tools/ @throws Ausnahmebehandlung @deprecated Veraltet. Compiler markiert Feld als veraltet + erzeugt Warnung @see Querverweis auf andere Javadoc-Docu oder andere Files in doc-files Verzeichnis Attribute und Methoden anderer Klassen mit # vor ihrem Namen. Bsp: {@link} @see meineMethode(String, Object) @see java.lang.String @see java.lang.Math#PI Verweise innerhalb DK-Text Bsp: Ändert Aufrufwert auf {@link #getValue} wenn nötig. {@code} Erläuternde Code-Auszüge Bsp: @throws IndexOutOfBoundsException bzgl. Index. ( {@code index <0 || index>=size()} ) Programmieren 2 - H.Neuendorf (74) JavaDoc + JAR mit Eclipse Alle Tools auch direkt mit diversen Optionen auf Kommandozeile ausführbar JavaDoc 1. Ordner für die durch JavaDoc erstellten Files anlegen 2. Menü: Project → Properties → JavaDoc Location 3. Aufruf von JavaDoc : Project → Generate JavaDoc Alternativ Kontextmenü : Alle JavaDoc-Optionen einstellbar Export → Java → Javadoc JAR-Files Projekt Kontextmenü : Export → Java → JAR file Wizzard erfagt Einstellungen bzgl. Ablageort + Inhalt → Runnable JAR File (Manifest-Datei !) Ein .jar-File mit Manifest-Eintrag für zentrale main( ) -Klasse ist direkt ausführbar Aufruf Launcher java mit Option -jar auf Kommandozeile : Vorteil jar : C:\> java –jar Test.jar ↵ Organisation & Kompression Weitergabe Projekt als ein File - statt Vielzahl von Files Remote-Aufruf : Alle .class-Files verfügbar - nicht einzeln übers Netz zu laden Programmieren 2 - H.Neuendorf (76) Weitere Tools jps … im bin-Ordner der JDK-Installation (JVM Process Status Tool) Anzeige laufender Java-Instanzen mit ProcessID (PID) jps jmap (JVM Memory Map) Anzahl + Speicherverbrauch aller Objekte zu bestimmter PID jmap –histo 5460 jstack (JVM Runtime Stack) Anzeige aller laufenden Threads und deren (Warte-)Zustand (Full Thread Dump) jstack 5460 jstat (JVM Statistics Monitoring Tool) Abfrage von Performance-Statistiken jstat –gcutil 4176 Aufruf auf Kommandozeile Option –help zur Orientierung Ausführliche Dokumentation in JDK-Doku : http://download.oracle.com/javase/8/docs/technotes/tools/ Programmieren 2 - H.Neuendorf (77) Weitere Tools jconsole im bin-Ordner JDK JVM Management Konsole für wählbaren Java-Prozess Programmieren 2 - H.Neuendorf (78) Paket java.lang Java SE Ausschnitt … java.lang Systemklassen Wrapper System Runtime RuntimePermission Process ProcessBuilder Thread ThreadGroup ThreadLocal<T> InheritableThreadLocal<T> Thread.State ClassLoader SecurityManager Class<T> Compiler Package StackTraceElement Boolean Byte Character Character.Subset Character.UnicodeBlock Double Float Integer Long Short Void Number Ausnahmebehandlung Throwable Exception NullPointerException ArrayIndexOutOfBounds-Exception ClassCastException ClassNotFoundException NumberFormatException SecurityException Error InternalError NoClassDefFoundException … Sonstiges Object Math StrictMath String StringBuffer StringBuilder … Interfaces Appendable CharSequence Cloneable Comparable<T> Iterable<T> Readable Runnable Thread.UncaughtExceptionHandler Wegen elementarer Bedeutung automatisch importiert Programmieren 2 - H.Neuendorf (79) Java SE Java SE Basis java.lang java.lang.instrument java.lang.reflect java.util java.util.concurrent java.util.jar java.util.zip java.util.regex java.math javax.management Text java.text javax.swing.text javax.swing.text.html javax.swing.text.rtf Grafik java.awt java.awt.color java.awt.dnd java.awt.event java.awt.image java.awt.font java.awt.geom javax.swing javax.swing.event Komponenten java.beans java.lang.reflect ... und zahlreiche weitere ... Ein-/ Ausgabe Netz/ Web java.io jawa.awt.print java.awt.im javax.imageio javax.print javax.sound.midi java.net javax.net java.nio java.applet java.rmi javax.rmi javax.rmi.ssl java.rmi.server java.security java.security.cert javax.naming Daten / SQL java.sql javax.sql javax.sql.rowset java.awt.datatransfer javax.crypto XML javax.xml javax.xml.parsers javax.xml.transform javax.xml.validation javax.stax javax.xml.xpath org.w3c.dom org.xml.sax Programmieren 2 - H.Neuendorf (80) Java EE Applikationsserver : Java Standard Client-Server-Transaktionalität JEE Basiert aufJava SE ! Servlets / JSP javax.servlet javax.servlet.jsp javax.servlet.http Enterprise Java Beans javax.ejb Grundlegende Überarbeitung durch Version EJB 3.0 ab Java EE 5 Kein Produkt - sondern Spezifikation Java EE-Server müssen Spezifikation implementieren, um zertifiziert zu werden. Mail Message Queues javax.mail javax.mail.event javax.activation javax.jms Oracle-Referenzimplementation GlassFish OpenSource J2EE-Server JBoss Vereinfachung der EJBImplementierung + Verteilung. Kommunikation javax.ressource javax.xml.rpc javax.xml.rpc.handler javax.xml.rpc.server javax.xml.rpc.soap javax.xml.soap Datenzugriff javax.transaction javax.xml.namespace javax.xml.parsers javax.xml.rpc javax.xml.registry javax.xml.transform javax.xml.transform.dom javax.xml.sax management javax.management ... und weitere ... Programmieren 2 - H.Neuendorf (82) Java Micro Edition Einsatz Java ME auf Geräten mit geringer Hardwareausstattung : Frühere Java-Handys … Java Micro Edition Basis Ein-/ Ausgabe java.lang java.util java.io Spezial-APIs javax.microedition.io javax.microedition.lcdui javax.microedition.rms Basiert auf Miniversion der virtuellen Maschine = KVM Erweiterungen im Bereich GUI, Netz ... Aktuelle Bedeutung gering aufgrund Android-Framework Aussicht : Nutzung für embedded devices und Machine2MachineKommunikation im IoT Java ME Wireless Toolkit IDE incl. Emulatoren Programmieren 2 - H.Neuendorf (83)