Vorlesung Informatik 1

Werbung
Vorlesung Informatik 1
Fachhochschule für Technik Esslingen
Studiengang Wirtschaftsinformatik
Teil 4: Bibliotheken
Dr. rer. nat. Andreas Rau
http://www.hs-esslingen.de/~rau
[email protected]
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#1
Inhalt
Dieser Teil der Vorlesung behandelt die wichtigsten Standardpakete von Java
und die darin enthaltenen Klassen. Davon ausgenommen sind die Pakete und
Klassen zur Oberflächenprogrammierung. Diese werden zu einem späteren
Zeitpunkt eigenständig behandelt.
Kein Mensch kann sich alle Details merken. Daher ist es beim Umgang mit den
hier beschriebenen Klassen immer wieder wichtig und richtig, auf die
Klassenreferenz zurückzugreifen um dort die Methoden der jeweiligen Interfaces
und Klassen nachzuschlagen (Wink mit dem Zaunpfahl!).
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#2
Klassen für Datenstrukturen - Hintergrund
Die fundamentale Datenstruktur in Java ist die Klasse. Diese stellt eine
Erweiterung der in anderen Klassen bekannten Strukturen oder Records dar.
Alle weiteren Datenstrukturen sind mit Hilfe von Klassen realisiert.
Dies gilt auch für Arrays, die einfachste Datenstruktur. Jedoch wird der Einsatz
von Arrays in Java durch besondere syntaktische Konstrukte unterstützt.
Dadurch sind Arrays nicht direkt als Objekte erkennbar. Ungeachtet dessen
spielt die Objekteigenschaft von Arrays an vielen, z.B. bei der
Parameterübergabe, eine wichtige Rolle.
Arrays sind aber nicht immer die beste Lösung. Deshalb gibt es in Java unter der
Sammelbezeichnung "Collections" eine Reihe weiterer Klassen, die andere
Datenstrukturen implementieren. Diese sind im Paket java.util untergebracht
(Arrays sind Bestandteil des Kerns bzw. von java.lang).
Kennzeichnend für alle Collection Klassen ist außerdem, dass Sie anders als
Arrays nicht individuell typisiert sind, sondern Objekte verwalten und dabei auch
verschiedene Typen mischen können.
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#3
Eigenschaften von Datenstrukturen(1)
Klassen wie die Collections in Java werden in anderen Programmiersprachen
auch als Container bezeichnet. Dieser Begriff hat in Java jedoch bereits eine
andere Bedeutung bzgl. grafischer Oberflächen.
Bei der Charakterisierung dieser Klassen unterscheidet man oftmals zwischen
der Schnittstelle ("wie kann die Datenstruktur genutzt werden?", "Wie verhält
sich die Datenstruktur?") und der Implementierung ("Wie ist die Datenstruktur
intern organisiert?").
Diese beiden Aspekte sind zunächst weitgehend voneinander unabhängig, d.h.
man kann
durch geeignete Kombinationen von Schnittstellen und
Implementierungen maßgeschneiderte Container erzeugen.
Historischer Hinweis: Collections waren bereits in Smalltalk-80 enthalten(!)
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#4
Eigenschaften von Datenstrukturen(2)
Eine Datenstruktur kann durch folgende Eigenschaften charakterisiert werden:
Zugriff
● Wahlfrei über Index oder Schlüssel
● Sequentiell durch "abklappern"
● Verhalten
● Fähigkeit automatisch zu wachsen oder zu schrumpfen
● Fähigkeit zum Einfügen in der Mitte
● Logische Organisation
● Mit / Ohne Duplikate
● Geordnet / ungeordnet
● Sortiert / unsortiert
● Physikalische Struktur
● Lineare Anordnung (statisch)
● Verzeigerung (dynamisch, verschiedene Strukturen)
●
Dabei bestehen natürlich auch Abhängigkeiten zwischen den verschiedenen
Eigenschaften – nicht alle Kombinationen sind ohne weiteres möglich.
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#5
Collection Klassen(1) - Überblick
In Java gibt es 3 große Familien von Collection Klassen
Listen
● Sets
● Maps
●
Alle diese Klassen implementieren das Interface Collection und sind von der
gemeinsamen Oberklasse AbstractCollection abgeleitet die einige
elementare Methoden zur Verfügung stellt. Daneben gibt es noch die Klasse
Collections die eine Reihe von nützlichen Hilfsmethoden implementiert.
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#6
Collection Klassen(2) - Listen
Als Listen bezeichnet man Klassen, die das Interface List implementieren.
Dies sind die Klassen ArrayList, Vector, Stack und LinkedList. Die
gemeinsame Oberklasse dieser Klassen ist AbstractList.
Kennzeichnend für Listen ist, dass man Elemente leicht einfügen oder anhängen
kann und direkt über einen Index auf Sie zugreifen kann. Diese gemeinsame
Schnittstelle entspricht auch der Anschauung einer Liste. Die Elemente werden
intern geordnet abgelegt. Die Klasse Stack bietet außerdem spezielle
Zugriffsmethoden für die Betrachtung als Stapel.
Jedoch bestehen wesentliche Unterschiede bzgl. der internen Implementierung:
Während ArrayList und Vector ihre Elemente linear im Speicher ablegen
(schneller Zugriff) sind diese bei der LinkedList explizit verzeigert (schnelles
Einfügen*).
vgl. Experimente zur Geschwindigkeitsmessung über System.currentTimeMillis()
* Die Navigation zur Einfügestelle kann hier allerdings länger dauern (besser: Einfügen mit ListIterator)!
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#7
Collection Klassen(2a) - Listen
List
AbstractList
(Interface)
© Andreas Rau, 14.12.07
(Basisklasse)
ArrayList
LinkedList
(Implementierung 1)
(Implementierung 2)
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#8
Collection Klassen(2b) - Listen
Implementierungsvariante 1: ArrayList
angehängt
Schneller Zugriff über Indexberechnung
verschieben
Dynamisches Wachsen
Einfaches Anhängen
eingefügt
© Andreas Rau, 14.12.07
Einfügen durch Verschieben (langsam)
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#9
Collection Klassen(2c) - Listen
Implementierungsvariante 2: LinkedList
null
null
Langsamer Zugriff durch "Durchhangeln"
Dynamisches Wachsen
Einfaches Anhängen
Einfügen durch Einklinken (schnell)
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#10
Collection Klassen(3) - Sets
Als Sets bezeichnet man Klassen, die das Interface Set implementieren. Dies
sind die Klassen HashSet und TreeSet. Die gemeinsame Oberklasse dieser
Klassen ist AbstractSet.
Kennzeichnend für Sets ist, dass keine doppelten Elemente gespeichert werden
können. Die Elemente werden intern ungeordnet abgelegt. Es ist leicht Elemente
einzufügen, zu entfernen und die Anwesenheit eines bestimmten Elements zu
überprüfen. Dafür ist kein direkter Zugriff auf einzelne Elemente möglich. Diese
gemeinsame Schnittstelle entspricht auch der Anschauung einer
mathematischen Menge.
Wieder bestehen wesentliche Unterschiede bzgl. der internen Implementierung
der Elemente (unterschiedliche Implementierungen): Während die Klasse
HashSet ihre Elemente in einer Tabelle verwalten sind diese beim TreeSet in
einer Baumstruktur hinterlegt.
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#11
Collection Klassen(3a) - Mengen
Set
AbstractSet
(Interface)
© Andreas Rau, 14.12.07
(Basisklasse)
HashSet
TreeSet
(Implementierung 1)
(Implementierung 2)
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#12
Collection Klassen(4) - Maps
Als Maps bezeichnet man Klassen, die das Interface Map implementieren. Dies
sind die Klassen HashMap, IdentityHashMap, TreeMap und WeakHashMap Die
gemeinsame Oberklasse dieser Klassen ist AbstractMap und ist nicht von
Collection abgeleitet.
Kennzeichnend für Maps ist, dass über einen Schlüssel direkt auf Objekte
zugegriffen werden kann. Dieser Schlüssel kann ein beliebiges Objekt sein. Die
Elemente werden intern ungeordnet abgelegt. Es ist leicht Elemente einzufügen,
zu entfernen und die Anwesenheit eines bestimmten Elements zu überprüfen.
Diese gemeinsame Schnittstelle entspricht auch der Anschauung einer
Zuordnungstabelle (Mapping). Ähnliche Klassen werden in anderen
Programmiersprachen auch als Assoziative Arrays oder Dictionaries bezeichnet.
Auch hier (gähn!) bestehen wesentliche Unterschiede bzgl. der internen
Implementierung der Elemente (unterschiedliche Implementierungen): Während
die Klassen HashMap, IdentityHashMap und WeakHashMap ihre Elemente in
einer Tabelle verwalten sind diese bei der TreeMap in einer Baumstruktur
hinterlegt.
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#13
Collection Klassen(4a) - Maps
Map
AbstractMap
(Interface)
© Andreas Rau, 14.12.07
(Basisklasse)
HashMap
TreeMap
(Implementierung 1)
(Implementierung 2)
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#14
Einschub: Hashing Verfahren(1)
Bei der Datenspeicherung mittels Hashing wird zunächst für jedes Objekt der
sog. Hashwert berechnet. Anhand dieses Werts wird ähnlich wie der Index bei
einem Array verwendet, um einen Speicherplatz auszuwählen. Da jedoch
verschiedene Objekte den selben Hashwert haben können, ist an diesem
Speicherplatz kein einzelnes Objekt sondern eine Liste von SchlüsselWertepaaren hinterlegt.
Beim Zugriff wird diese Liste nach einem Paar durchsucht, dessen Schlüssel
gleich dem angefragten Schlüssel ist. Dabei kann durch Sortierung und binäre
Suche eine weitere Beschleunigung erreicht werden (lineare Suche: Zugriff in
n/2 Schritten, binäre Suche: Zugriff in log(n)/log(2) Schritten).
Damit dies funktioniert muss sichergestellt sein, dass gleiche Objekte auch
denselben Hashwert haben. Dies muss beim Überschreiben der Methoden
equals() bzw. hashCode() beachtet werden (siehe dazu auch die
entsprechenden Beispielprogramme). Die Zugriffsgeschwindigkeit ist umso
höher, je weniger Objekte denselben Hashwert haben. Damit kommt der
Hashfunktion die diesen Wert berechnet eine wichtige Bedeutung zu
(Anforderungen: schnelle Berechnung und breite Streuung).
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#15
Einschub: Hashing Verfahren(2)
Zugriff Teil 2
durch Suche mit equals()
Zugriff Teil 1
mit index lt.
hashCode()
Liste(n) mit Objekte die
den gleichen hashCode haben
interne
Hashtable
Wenn nicht "o1.equals( o2) => o1.hashCode() == o2.hashCode()",
d.h. wenn gleiche Objekte unterschiedliche hashCodes haben ist
funktioniert dieses zweischrittige Verfahren nicht!
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#16
Elementare Datentypen und Collections – Wrapper Klassen
Im Unterschied zu Arrays speichern Collection Klassen allgemeine Objekte. Dies
bedeutet zunächst, daß beim Zugriff auf Elemente vor deren Verwendung i.d.R.
ein cast auf den speziellen Objekttyp notwendig ist.
Außerdem ist es nicht möglich, elementare Datentypen in einer Collection zu
speichern. Ein ähnliches Problem stellt sich auch bei verallgemeinerten
Algorithmen, die auf Objekten operieren und kann durchaus als Designfehler von
Java betrachtet werden.
In beiden Fällen müssen von elementaren Datentypen als Objekt verpackt
werden. Um dies nicht immer wieder selbst tun zu müssen, steht für jeden
elementaren Datentyp eine Wrapperklasse zur Verfügung. Die Namen der
Wrapperklassen ergeben sich aus der großgeschriebenen Langform des
Typnamens, z.B. int / Integer, boolean / Boolean. Instanzen dieser Klassen
kapseln einen Wert des zugehörigen elementaren Datentyps und stellen
daneben eine Reihe von Hilfsmethoden, u.a. zum Einlesen und Ausgeben von
Werten zur Verfügung.
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#17
Autoboxing
Mit Java 5.0 packt der Compiler die Werte automatisch aus und ein.
import java.util.*;
import java.util.*;
public class NewSchool { // ab Java 1.5 public class OldSchool { // bis Java 1.4
public static void main( String[] args) {
public static void main( String[] args) {
List l = new ArrayList();
List l = new ArrayList();
}
l.add( 5); // Autobox-in
int i = (Integer)l.get(0); // Autobox-out
l.add( new Integer( 5));
int i = ((Integer)l.get(0)).intValue();
// new Integer(1);
Integer A = 1;
// new Integer(2);
Integer B = 2;
// int s = A.intValue() + B.intValue()
int s = A+B;
int a = 5;
int b = 6;
int s = a+b;
}
}
}
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#18
Bearbeiten von Collections - Iteration
Collections dienen nicht nur zum Verwalten sondern auch zum Bearbeiten von
Elementen. Dabei kommt es häufig vor, daß eine Operation auf alle Elemente
einer Collection angewendet werden soll. Bei Arrays würde man hierfür eine forSchleife verwenden.
for (int i=0; i<objects.length; i++) { // objects ist ein Array
Object element = objects[i];
System.out.println( element);
}
Diese Iteration läßt sich für Collections folgendermaßen verallgemeinern.
Iterator iter = objects.iterator(); // objects ist eine Collection
while (iter.hasNext()) {
Object element = iter.next();
System.out.println( element);
}
Dabei entspricht der Iterator dem Array-Index. Zu jeder Collection Klasse gibt es
eine eigene Iteratorklasse die das Interface Iterator implementiert.
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#19
Bearbeiten von Collections - Iteration
Der Iterator ist dabei ein für den jeweiligen Typ der Collection spezifisches
Objekt, wird aber genau wie die Collections selbst nur über das entsprechende
Interface verwendet. Noch einfacher geht das ganze mit der neuen for-Schleife:
Object[] objects = { "la", "li", "lu" };
for (Object element : objects) { // objects ist ein Array
System.out.println( element);
}
Diese Art der Iteration läßt sich 1:1 auf Collections anwenden
List objects = new ArrayList();
objects.add( "la");
objects.add( "li");
objects.add( "lu");
for (Object element : objects) { // objects ist eine Collection
System.out.println( element);
}
Ist doch genial, wie sich hier alles bisher gelernte zusammenfügt...
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#20
Collection Klassen (5) – Vergleich mit Arrays
Die wesentlichen Einschränkungen bei Arrays sind:
feste Größe (Abhilfe: alle Collections)
● fester Datentyp für Elemente (Abhilfe: alle Collections*)
● numerischer Index (Abhilfe: Maps)
●
Dies muss nicht immer von Nachteil sein. Gerade diese Eigenschaften sind es
nämlich, die eine sehr effiziente Implementierung von Arrays ermöglichen.
Man kann eben im Leben wie in der Programmierung einfach nicht alles haben
(hier: Flexibilität und Geschwindigkeit).
* Verwaltung über Klasse Object. Bei Entnahme von Objekten ist ein cast
notwendig. Primitive Datentypen nur mit Hilfe von Wrapperklassen speicherbar.
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#21
Collection Klassen (6) – Illustration und Merkhilfe
Arrays
Listen
a[0]
l.get(0)
a[1]
l.get(1)
a[2]
l.get(2)
Größe:
beschränkt
Zugriff:
wahlfrei
Struktur: geordnet
© Andreas Rau, 14.12.07
variabel
variabel
geordnet
Sets
variabel
variabel
ungeordnet
Maps
variabel
variabel
ungeordnet
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#22
Collection Klassen(7) - Fazit
Folgende Eigenschaften gelten für alle Collections
Collections bieten "Datenstrukturen für alle Lebenslagen"
● Collections können mit beliebigen Objekten verwendet werden.
● Zu jeder Familie von Collections gibt es Interface und Basisklasse
●
Variablen sollten stets mit Hilfe der Interfaces deklariert werden. Dies gilt auch
für Übergabeparameter von Algorithmen. Da es normalerweise nur auf das
Verhalten der Collection ankommt und dieses über das Interface voll zugänglich
ist ermöglicht dies einen problemlosen Wechsel innerhalb der Varianten eines
Collection-Typs (z.B. Ersatz von ArrayList durch LinkedList).
Beispiel
// problemloser Ersatz durch new LinkedList()
List myList = new ArrayList();
Die konkrete Klasse sollte also nur verwendet werden, wenn spezielle
Eigenschaften der Klasse verwendet bzw. gefordert werden (kommt so gut wie
nie vor). Die Basisklasse kann ggf. für eigene Implementierungen verwendet
werden (kommt noch seltener vor).
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#23
Ein-/Ausgabe mit Streams - Hintergrund
Die Flexibilität von Software gründet sich neben ihrer Anpassbarkeit darauf, dass
man Sie mit unterschiedlichsten Daten füttern kann. Daher ist die Ein- und
Ausgabe von Daten ein elementarer Bestandteil von Programmen.
Doch Eingabe woher und Ausgabe wohin? Tastatur, Maus, Netzwerk,
Laufwerke, Bildschirm, Drucker, ... obwohl es sich hier physikalisch um
unterschiedliche Geräte handelt, kann man sie alle logisch verallgemeinert als
Datenquellen und -senken mit bestimmten Eigenschaften betrachten.
Daraus folgt der Wunsch, diese Geräte auch in der Software möglichst gleich zu
behandeln und ihre Gemeinsamkeiten zu einer einheitlichen Schnittstelle
zusammenzufassen bzw. ihre Unterschiede dahinter zu verstecken. Dadurch
steigt die Flexibilität der Software und es ist sehr einfach eine Datenquelle oder
-senke gegen eine andere auszutauschen.
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#24
Ein-/Ausgabe mit Streams - Konzept(1)
Das Konzept zur Verallgemeinerung von Datenquellen und -senken sind (nach
alter Unix-Tradition) sogenannte Datenströme oder Streams. Ein Stream ist
zunächst einmal ein Kanal, der Daten liefern oder abtransportieren kann. Auf der
elementarsten Ebene werden diese Daten als Folge von Bytes betrachtet.
Eine wesentliche Eigenschaft des Stream Konzepts ist die Möglichkeit, mehrere
Streams zu verketten, d.h. wie Rohre ineinanderzustecken. Die aufgesteckten
Streams agieren quasi als Filter (dieser Begriff ist tatsächlich gebräuchlich) und
erlauben es, den ursprünglichen Bytestrom als eine Folge von Zeichen, Zahlen
oder Objekten zu interpretieren oder weitere Eigenschaften wie Pufferung,
Kompression, Verschlüsselung o.ä. zu realisieren. Dies funktioniert sowohl bei
der Eingabe als auch bei der Ausgabe von Daten.
Quelle
Senke
© Andreas Rau, 14.12.07
Stream
(Bytes)
Filter 1
(Zip)
Filter 2
(Objects)
Stream
(Bytes)
Filter 1
(Zip)
Filter 2
(Objects)
read
write
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#25
Ein-/Ausgabe mit Streams - Konzept(2)
Die konkrete Datenquelle oder -senke für den grundlegenden Stream kann
entweder ein Gerät (Tastatur/Bildschirm), eine Datei, das Netzwerk oder ein
Objekt im Hauptspeicher (String oder Array) sein.
Das Tolle ist, das die konkrete Datenquelle oder -senke mit Ausnahme der
Streamerzeugung praktisch keinen Unterschied macht, da alle grundlegenden
Streams die gleiche Schnittstelle besitzen und die nachfolgenden Filter mit
jedem von Ihnen arbeiten können.
Damit kann ein Programm auf ein und dieselbe Art und Weise mit Daten aus
unterschiedlichsten Quellen arbeiten. Die Kombinationsmöglichkeiten der
verschiedenen Filter ermöglichen dabei ein Höchstmaß an Flexibilität und
Wiederverwendung.
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#26
Stream Klassen(1)
Die Stream Klassen in Java sind im Paket java.io untergebracht und lassen
sich in InputStreams (für die Eingabe) und OutputStreams (für die Ausgabe)
einteilen die jeweils von der gleichnamigen abstrakten(!) Basisklasse
InputStream bzw. OutputStream abgeleitet sind.
Diese Basisklasse definieren elementare Methoden für die Ein-/Ausgabe von
Bytes. Ihre konkreten Subklassen wie z.B. FileInputStream implementieren
diese Methoden für die Arbeit mit verschiedenen Datenquellen bzw. -senken.
Daneben gibt es ein je eine weitere Klasse (z.B. FilterInputStream), die als
abstrakte Basisklasse für diverse Filter dient. Diese erlauben die Bearbeitung
des elementaren Bytestroms, z.B. Pufferung (z.B. BufferedInputStream),
Komprimierung (z.B. ZipInputStream) oder "Interpretation" als Werte
elementarer Datentypen (z.B. DataInputStream).
Die Klassen zur Ein-/Ausgabe von Objekten, ObjectInputStream und
ObjectOutputStream, sind eigentlich Filter, erben aber trotzdem direkt von den
jeweiligen abstrakten Streamklassen.
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#27
Stream Klassen(2)
Zur Verkettung von Filtern bzw. Streams muss bei der darunterliegende Stream
bei der Konstruktion des darüberliegenden angegeben werden.
Quelle
Stream
(Bytes)
Filter
(Data)
read
Beispiel:
import java.io.FileInputStream;
import java.io.DataInputStream;
// ...
FileInputStream fi = new FileInputStream( "myfile.dat");
DataInputStream di = new DataInputStream( fi);
double d = di.readDouble();
di.close();
Die Klasse System stellt mit den Klassenvariablen err, in und out drei Streams
für die Ein-/Ausgabe über Tastatur und Bildschirm zur Verfügung. Die beiden
Ausgabestreams sind in Wirklichkeit Filterketten, der Eingabestream ist direkt.
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#28
Serialisierung
Bei der Ein-/Ausgabe von Objekten muss unter anderem die Klasse sowie der
Wert aller Attribute einzeln verarbeitet werden. Glücklicherweise muß man dies
nicht manuell implementieren: Über das Interface Serializable können
beliebige Klassen für die automatische Ein-/Ausgabe markiert werden.
Beispiel
public class Auto implements Serializable {
// ...
}
// in einer anderen Klasse:
Auto a = new Auto( "Ford", "Fiesta");
FileOutputStream fos = new FileOutputStream( "objects.dat")
ObjectOutputStream oos = new ObjectOutputStream( fos);
oos.writeObject( a);
oos.close();
Dieser automatische Vorgang kann bei Bedarf durch überschreiben der
Methoden readObject() und writeObject() angepasst werden. Dies ist
jedoch nur in Ausnahmefällen notwendig.
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#29
Reader und Writer
Die Ein-/Ausgabe von Zeichen ist wegen deren unterschiedlicher Kodierung nur
in Ausnahmefällen direkt über Streams möglich. Während der westeuropäische
ISO-Latin-1 Zeichensatz weitgehend dem ASCII Zeichensatz entspricht und mit
einem Byte pro Zeichen auskommt, sind im allgemeinen Fall mit Unicode zwei
oder mehr Bytes pro Zeichen notwendig.
Daher gibt es in Java spezielle Klassen zur Ein-/Ausgabe von Zeichen, die sog.
Reader und Writer die wiederum von zwei gleichnamigen abstrakten
Basisklassen abgeleitet sind. Reader und Writer können Text zeichen- und/oder
zeilenweise ein- und ausgeben und berücksichtigen dabei automatisch die
jeweils gültige Kodierung.
Die Systematik der darunterliegenden Klassen ist ähnlich wie bei den Streams:
Es gibt direkte konkrete Subklassen für die Anbindung verschiedener
Datenquellen und -senken sowie eine Zwischenklasse für Filter. Durch die
Fokussierung auf Text ist jedoch die Vielfalt, insbesondere bei den Filtern, nicht
so zahlreich. Reader bzw. Writer sind jedoch selbst auch Filter und können auf
Streams und deren Filter "aufgesteckt" werden.
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#30
Ein-/Ausgabe - Überblick
Ein-/Ausgabe (I/O)
Paket java.io
Byteorientiert
Zeichenorientiert
Eingabe
Ausgabe
Eingabe
Ausgabe
(abstrakt)
InputStream
(abstrakt)
OutputStream
(abstrakt)
Reader
(abstrakt)
Writer
(konkret)
FileInputStream
(konkret)
FileOutputStream
(konkret)
FileReader
(konkret)
FileWriter
(filter)
BufferedInputStream
ByteArrayInputStream ByteArrayOutputStream
CharArrayReader
InputStreamReader
CharArrayWriter
OutputStreamWriter
(filter)
(filter)
(filter)
BufferedOutputStream
BufferedReader
BufferedWriter
DataInputStream DataOutputStream
ObjectInputStreamObjectOutputStream
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#31
Ein-/Ausgabe - Fazit
Streams und damit die zugehörigen Datenquellen und -senken können ähnlich
wie Collections ausgetauscht werden, ohne das am Code viel geändert werden
muss, da die Schnittstelle stets dieselbe bleibt.
Aufbauend auf dieser gemeinsamen Schnittstelle können den elementaren
Streams über Filter spezifische Eigenschaften flexibel aufgeprägt werden. Dabei
lassen sich auch verschiedene Filter durch Verkettung kombinieren. Auf diese
Art und Weise ist ein Höchstmaß an Flexibilität und Wiederverwendung möglich.
Damit stellen die Streams und die zugehörigen Reader und Writer und Filter eine
vielseitige, mächtige und erweiterbare Menge von Klassen dar. Der Aufbau der
zugehörigen Klassenbibliothek folgt einer einfachen Systematik:
Abstrakte Basisklassen zur Festlegung der elementaren Schnittstelle
● Konkrete Subklassen zur Anbindung verschiedener Datenquellen und -senken
● Abstrakte Subklasse für Filter
● Konkrete Subklassen zur Implementierung der Filter
●
© Andreas Rau, 14.12.07
D:\home\ar\fhte\vorlesungen\informatik1\folien\informatik1-theorie-bibliotheken.odp
#32
Herunterladen