Java FH Merseburg SS 2002 String Übung: Ziel: Zugriff auf die Stringkomponenten und Auswertung Zählen der Häufigkeit eines Buchstabens: public class ZeichenZaehler { public static void main (String args[]) { String str = new String ("Java ist eine interessante Sprache."); long zeichenZaehler[] = new long [256]; // 65536 for (int i = 0; i < str.length(); i++) zeichenZaehler[str.charAt(i)] ++; for (int i = 0; i < zeichenZaehler.length; i++) if (zeichenZaehler[i] > 0) System.out.println((char)(i) + "\t[" + i + "]\t- " + zeichenZaehler[i] + " mal"); wait a = new wait(); a.waitForReturn(); } } 481353149 . J S a c e h i n p r s t v [32] - 4 mal [46] - 1 mal [74] - 1 mal [83] - 1 mal [97] - 4 mal [99] - 1 mal [101] - 6 mal [104] - 1 mal [105] - 3 mal [110] - 3 mal [112] - 1 mal [114] - 2 mal [115] - 3 mal [116] - 3 mal [118] - 1 mal Druecken Sie ENTER ... -1- Java 2.10 FH Merseburg SS 2002 Rückgabe von mehreren Werten Rücklieferung von Werten einer Methode an die aufrufende Methode Rückgabewert ist ein Feld, das alle Werte desselben Objekttyps aufnimmt ein Objekt kann als Parameter übergeben werden, und dessen Daten werden von der Methode geändert innerhalb der aufgerufenen Methode wird ein neues Objekt erzeugt, das die Daten aufnimmt und als Rückgabewerte an die aufrufende Methode zurückliefert // Daten-Container zur Aufnahme verschiedener Attribute // vergleichbar mit struct in C class GeoFigDaten { public double laenge; public double breite; // z.B. 7.0 // z.B. 6.0 // Konstruktor GeoFigDaten () { this.laenge = 7.7; this.breite = 6.6; } // Konstruktor GeoFigDaten (double this.laenge = this.breite = } // mehrere Methoden laenge, double breite) { laenge; breite; zum setzen und lesen der Attribute } Bearbeitung der Daten in einer anderen Klasse Rückgabe mit Objekt der Containerklasse und Rückgabe ueber Parameter Objekt // Klasse aendert die Daten im Datencontainer class GFDAendern { // liefert die Daten ueber ein Rueckgabe Objekt zurueck public GeoFigDaten GFDerstellen () { GeoFigDaten neudaten = new GeoFigDaten(); // Benutzereingaben moeglich neudaten.laenge = 8.0; neudaten.breite = 9.0; return neudaten; } // aendert Daten in Objekt, das als Parameter uebergeben wurde public void GFDerstellen (GeoFigDaten x) { // Benutzereingaben moeglich x.laenge = 11.0; x.breite = 12.0; } } 481353149 -2- Java FH Merseburg SS 2002 Benutzung des Datencontainers und der Methode in Main-Methode: // Problem: Rueckgabe mehrerer Werte ueber eine "Daten-Klasse" GeoFigDaten: class Control { public static void main (String args[]) { // Erzeugen Instanz von GeoFigDaten (2 Konstruktoren) // Ausgabe der Attribute aus GeoFigDaten GeoFigDaten a = new GeoFigDaten(3.0,4.0); System.out.println("Laenge: " + a.laenge); System.out.println("Breite: " + a.breite); // benutzen einer M. GFDAendern zum Veraendern der Attribute // in GeoFigDaten mit Rueckgabe eines GeoFigDaten-Objektes // zuweisen des Rueckgabe-Objektes an eine Instanz GFDAendern b = new GFDAendern(); a = b.GFDerstellen(); System.out.println("Laenge: " + a.laenge); System.out.println("Breite: " + a.breite); // ... waitForReturn(); } } Speicherverwaltung (automatisch) und Garbage Collection Speicherbereich wird in Java durch Laufzeitsystem überwacht in anderen Programmiersprachen durch Programmierer z. B. Rückgabewert von malloc Löschen von Objekten mit new neues Objekt, aber kein delete in C durch Programmierer: malloc free Konstruktoren, aber keine Destruktoren in Java durch Java - Laufzeitsystem organisiert Garbage Collector gibt Speicherplatz frei, wenn Objekt nicht mehr referenziert wird immer wenn neue Objekte erzeugt werden und nicht genügend Speicherplatz zur Verfügung steht Garbage Collector das Ende der Referenzierung eines Objektes ist erreicht, wenn keine statische Objektkomponente das Objekt referenziert oder wenn keine z. Z. ausgeführte Methode eine Referenz zum Objekt besitzt (bei innerhalb der Methode erzeugten Referenzen wird diese beim Verlassen der Methode aufgelöst) a1 ... c1 A a1 ... von anderen Objekten 481353149 a2 ... b1 ... class A ... class B ... class C ... -3- Java FH Merseburg SS 2002 Java verwaltet die Anzahl der Referenzen auf ein Objekt sobald keine Referenzen auf ein Objekt existieren, wird es zur GC freigegeben (siehe Referenz auf C fehlt diese Referenz, dann Freigabe, danach auch Freigabe für a1, a2, b1 Möglichkeiten der Löschung: belegen durch null // = Objekt wird nicht mehr benutzt Beispiel public static void main (String args[]) { int ergebnis, feld[] = new int[100]; init_feld(feld); // Feld initialisieren ergebnis = verarb_Feld(feld); // und benutzen // ab hier wird feld nicht mehr benötigt feld = null; // Rest des Programms } Objekte können außer Speicher auch noch andere Ressourcen benutzen (Datei Streams, Netzwerkverbindungen etc.) GC darf diese Ressourcen nicht eigenmächtig freigeben daher ruft er vor der Freigabe die Methode finalize() auf, diese kann je Objekt definiert werden und sollte die Ressourcen selbst freigeben public class DateiRessourcen { private Stream File; public DateiRessourcen (String pfad) { File = new Stream (pfad); } // ... weitere Programmanweisungen public void close () { if (File != null) { File.close(); File = null; } } //Überschreibende Methode // Methode von Stream // in dieser Formulierung funktioniert close() auch bei // mehrfachem Aufruf protected void finalize() throws Throwable { super.finalize(); // sollte immer so gemacht werden // ansonsten ist eigene Klasse O.k. // aber Oberklassen evtl. problematisch close(); } kein Parameter und kein Rückgabewert Operationen können zu einem Fehler oder Ausnahmezustand führen anstoßen einer Ausnahmebehandlung durch Throwable eigene Fehlerbehandlung durch try/catch Schlüsselwort throws gibt an, welche Ausnahmen eine Methode erzeugen kann (throw = erzeugen von Exceptions) Klasse Throwable ist Oberklasse für alle Ausnahmeklassen 481353149 -4- Java FH Merseburg SS 2002 endet eine Anwendung werden die finalize() Methoden aller Objekte aufgerufen, wenn nicht ein Systemfehler (z. B. unzureichender Speicherplatz) dies verhindert expliziter Aufruf des GC mit : System.gc(); Beispiel Geofigur: public class GeoFigur { protected float Laenge; protected float Breite; protected float Flaeche; static protected int InstZaehler; // Konstruktor 1 public GeoFigur() { ++InstZaehler; } // Konstruktor 2 public GeoFigur(float x) { Länge = x; ++InstZaehler; } // Konstruktor 3 public GeoFigur(float x, float y) { Länge = x; Breite = y; ++InstZaehler; } public void finalize() { --InstZaehler; } // weitere Methoden zum Setzen und Lesen der Attribute public abstract float berechneVolumen(); } Abstrakte Klassen Grundlage: Basisklasse kann keine Instanzen erzeugen Ausgangspunkt war Vererbung – Übernahme von Attributen und Methoden in abgeleitete Klassen Beispiel Geofigur public class GeoFigur { protected float Länge; protected float Breite; protected float Fläche; static protected int InstCounter; // // // // Konstruktoren, wie z. B. public GeoFigur() {} public GeoFigur(float x) {} public GeoFigur(float x, float y) { } // public void finalize() {--InstCounter; } 481353149 -5- Java FH Merseburg SS 2002 // Methoden zum Setzen und Lesen public float setl(float x) { } public float getl() { } public float setb(float y) { } public float getb() { } diese Attribute und Methoden sind allgemeingültig, andere Methoden machen nur für konkrete Instanz Sinn, wie beispielsweise: public abstract float berechneFlaeche(); public abstract float berechneVolumen(); diese Methoden erhalten den Modifier abstract: abstrakte Methoden können nicht vom Typ static private oder final sein sie enthalten keine Methodendefinition beinhaltet eine Klasse eine abstrakte Methode, dann ist die Klasse selbst abstrakt Abstrakte Klassen sind durch das Schlüsselwort „abstract“ gekennzeichnet und können nicht als final deklariert werden. Sie können auch nicht instanziert werden. Soll eine abstrakte Klasse verwendet werden (im Beispiel die Ableitungen Dreieck, Rechteck, Kreis) muß die abstrakte Methode implementiert werden. Allen abgeleiteteten Klassen sind aber die abstrakten Methoden gemeinsam (gleiche Parameter und Rückgabewerte). Schnittstellen / Interfaces In manchen Fällen ist es sinnvoll, eine Klasse mit zwei oder mehr Basisklassen zu erzeugen Mehrfachvererbung Beispiel Leichtathlet Basisklasse: Leichtathlet Abgeleitet: Weitspringer – Hochspringer – 100m Läufer – Hürdenläufer ... Neue Klasse: Zehnkämpfer Erbt von bestimmten Klassen, die von Leichtathlet abgeleitet sind Übernimmt M und A von 10 Klassen Problem: sind in den Basisklassen Variablen oder Methoden mit gleichem Namen aber unterschiedlicher Ausprägung vorhanden Zuordnung schwierig Beispiel: Weitspringer und Hochspringer könnten M springe() enthalten Es muß aber konkret eine Methode angesprochen werden Alternativen: Es könnte eine Methode fest angesprochen werden aber Vorteile der Mehrfachvererbung gehen verloren Bei jedem Aufruf eine M explizit angeben z.B. Weitspringer.springe() auf dynamische Zuordnung von M. wird verzichtet 481353149 -6- Java FH Merseburg SS 2002 Mehrfachvererbung wird aber nur in wenigen Fällen wirklich nutzbringend eingesetzt Zehnkämpfer ist weder Weitspringer noch Hochspringer Interfaces Mit Schnittstellen überwindet Java die Einschränkungen der Einfachvererbung ohne die Nachteile der MFV in Kauf nehmen zu müssen IF definieren beliebige Anz. Von Methoden und Variablen und damit gleichzeitig eigenen Referenztyp Um eine Schnittstelle S zu implementieren muß eine Klasse C alle in de Schnittstelle enthaltenen Methoden konkret realisiseren Verpflichtung Schnittstelle kann andere Schnittstellen erweitern Allgemeine Form: [public] [abstract] interface InterfaceName [extends BasisInterface] { [public] [static] [final] Konstante1 = Wert1; ... [public] [abstract] Methode1(Argumentliste); } Jede Variable in Interface gilt automatisch als static und final es handelt sich um eine Konstante die ist zu initialisieren public interface Kalorien { public double lesenKalorien(); } Jede Klasse, die eine Methode lesenKalorien enthält, kann das Interface implementieren: public class SchokoKeks extends Keks implements Kalorien { private double kal; public double lesenKalorien() { return kal; } // .. weitere Methoden von SchokoKeks } Andere Klassen können Referenzen auf Objekte der Klasse Interface erzeugen und diesen Objekte der Klasse SchokoKeks zuweisen: public class A { Kalorien SKeks = new SchokoKeks(); System.out.println(Skeks.lesenKalorien()); ... } Nutzen von Interfaces: Wenn andere Klassen mit anderer Vererbungshierarchie ebenfalls das Interface imlementieren public class Pausenbrot extends Brot 481353149 -7- Java FH Merseburg SS 2002 implements Kalorien { ... public double lesenKalorien() { ... implementieren } } Pausenbrot und Schokokeks stammen von unterschiedlichen Vererbungshierarchien, implementieren aber die gleiche Schnittstelle. Klasse A kann daher über die Schnittstelle Kalorien die Methode lesenKalorien() aller betreffender Klassen aufrufen: public class A { Kalorien SKeks = new SchokoKeks(); Kalorien PBrot = new Pausenbrot(); System.out.println(Skeks.lesenKalorien()); System.out.println(PBrot.lesenKalorien()); ... } Packages jede Klasse in eigener Datei .class Ziel der Packages: Gliederung der Projektklassen und der Systembibliotheken Pakete enthalten inhaltlich zusammengehörende Klassen, Schnittstellen und Unterpakete. Alle Klassen gehören implizit zu einem Package, das unbenannt ist. spezielle Paketdeklaration: package ein.paket.name; class KlassenName {...} der PaketName ist implizit jedem im Paket enthaltenen Typnamen vorangestellt vor allen Klassen und Schnittstellendefinitionen der Klasse vollständiger Name für Package besteht aus Komponenten, die durch Punkte getrennt sind Korrespondez mit Verzeichnisstruktur (abhängig von Java-Implementation) Jede Komponente eines P-Namens kann einem bestimmten Verzeichnis des Rechners zugeordnet werden Klassen und Schnittstellen werden als einzelne Dateien im Verzeichnis gespeichert Namenswahl: Grundsätzlich beliebig, systemweite Packages Namenskonvention von Sun gewährleistet weltweit eindeutige Namen für P. Internet Domain Namen + interner PackageName Beispiele: Package Klasse 481353149 zugehörige Dateinamen: Meth -8- Java FH Merseburg SS 2002 java.lang.Thread.start() ../java/lang/Thread.class Package Kl Meth. com.ms.awt.image.getsize() ../com/ms/awt/image.class ../lib/classes.zip Package Kl DE.fh-fulda.informatik.pax.java.GeoFig.setB() M Pfadeinstellungen über CLASSPATH-Variable Zugriff: über den direkten Namen einschließlich vorangestelltem Paketbezeichner Klasse A in Package x.y.z x.y.z.A Eindeutige Referenz möglich: public class B { int f() { x.y.z.A = einA; x.y.z.A = nochEinA; ... einA = new x.y.z.A(); } } Problem: unübersichtlicher Quelltext import Import x.y.z.A; Import x.y.z.B; public class D { int g() { A a = B b = new A(); new B(); x.y.z.C c = new x.y.z.C(); ... // nicht imp. Name } } import von Teilen oder des ganzen Paketes Import x.y.z.A; Import x.y.z:*; Importiert nur die Klassen einer Ebene Unterpakete müssen selbst importiert werden. *** 481353149 -9-