Programme verarbeiten Daten Generische Datenstrukturen

Werbung
Vorlesung „Programmieren“
Java Generics und Java API
Prof. Dr. Stefan Fischer
Institut für Telematik, Universität zu Lübeck
https://www.itm.uni-luebeck.de/people/fischer
Programme verarbeiten Daten
• Häufig benötigt: Datenstrukturen zum Speichern
• Bisher: Spezielle Datenstrukturen pro Programm:
Security - 04 Cryptology
#2
Generische Datenstrukturen
• Häufig benötigte Datenstrukturen (ausführlich
in AuD im 2. Semester)
– Listen
– Keller bzw. Stapel (Stack)
– Warteschlangen (Queues)
– Mengen
– ...
• Natürlich kann man diese selbst
programmieren
Security - 04 Cryptology
#3
Beispiel: Eigene generische Liste
Security - 04 Cryptology
#4
Mögliche Implementierung
Speichert alle in Java
möglichen Objekte, da alle
transitiv von Objekt erben
Es können (bei dieser Implementierung)
maximal maxElemente gespeichert werden in
einer konkreten Instanz
Security - 04 Cryptology
#5
Mögliche Implementierung
Security - 04 Cryptology
#6
Mögliche Implementierung
Security - 04 Cryptology
#7
Mögliche Implementierung
Security - 04 Cryptology
#8
Mögliche Implementierung
• Was praktisches: schöne „Ausgabe“ der Instanz
Security - 04 Cryptology
#9
Verwendung
Security - 04 Cryptology
#10
Der Obstkorb und die Liste
Security - 04 Cryptology
#11
Problem dieser Implementierung
• Verwendung einer festen maximalen Größe
– Werden mehr Elemente eingefügt als Platz
verfügbar ist, werden diese nicht gespeichert
• Besser: dynamische Größenanpassung
– Liste sollte dynamisch „mitwachsen“
• Alternative Implementierung
– siehe nächste Folie
Security - 04 Cryptology
#12
Dynamische Liste
Security - 04 Cryptology
#13
Datenstrukturen und Java
• Dieses Problem betrifft praktisch alle Programme
– In vielen Sprachen (z.B. C) hat praktisch jedes Programm seine eigenen
Datentypen implementiert
– Probleme: viel unnötiger Code, Fehlerquelle, schwer auszutauschen,
jedes Programm war „einzigartig“ hohe Einarbeitungszeit
• Daher: Java stellt Standardtypen bereit
– Teil der Java Distribution
– Sog. „Java Collections Framework“ (java.util.*)
• Referenzen
– http://download.oracle.com/javase/tutorial/collections/
– http://download.oracle.com/javase/7/docs/api/
14
Java Collections Framework (JCF)
• Stellt sog. Container-Klassen bereit
– Container nehmen andere Datentypen in sich auf
– Dynamische Datenstrukturen, die ihre Größe anpassen
• Zwei grundlegende Typen: Collection und Map
– Collection (java.util.Collection)
in dieser Vorlesung
• Listen, Mengen, Schlangen (Queues)
– Map für Assoziativspeicher (java.util.Map)
• Speichert <name, wert>-Tupel
15
Java Collections Framework (JCF)
•
Interfaces legen den Funktionsumfang eines Containertyps fest
– z.B. das Interface Collection
•
Konkrete Klassen erben von diesen und implementieren die Funktion des
Containers
– Abstrakte Basisklassen dienen zur vereinfachten Implementierung konkreter
Klassen
•
Beispiel
Implementiert Interface „Collection“
Abstrakte Listenimplementierung
Konkret, Speicherung in Array
16
Teil der Vererbungshierarchie
Collection
AbstractList
ArrayList
...
AbstractSet
Vector
TreeSet
Security - 04 Cryptology
...
HashSet
#17
Collection Interface
• Wichtige Methoden
–
–
–
–
–
–
boolean add(E e);
void clear();
boolean contains(Object o);
int size();
Iterator iterator();
...
• Was ist wohl ein Iterator?
– Später...
Security - 04 Cryptology
#18
Interface java.util.Collection
19
Instanziierung einer Collection
• Beispiel: Verwendung einer Liste
– Zunächst Wahl einer Implementierung
– Dann Instanziierung
•Collection c = new ArrayList();
20
Verwendung von Collection
import java.util.*;
public class NutzungVonCollection {
private static void test( Collection c ) {
for ( int i = 0; i < 5; i++ )
c.add( i );
System.out.println(“Ist leer? “ + c.isEmpty());
System.out.println(
“Anzahl Elemente: “ + c.size());
}
}
21
Konzept der Iteratoren
• Dient dem Zugriff auf Elemente einer Collection
– Im einfachsten Fall kann man nur vorwärts von einem Element zum
nächsten gelangen
– Iterator iterator = collection.iterator();
• Zwei wesentliche Methoden eines Iterators
– boolean hasNext(): true, wenn es ein weiteres Element gibt
– Object next(): Liefert nächstes Objekt
• Beispiel: Iteration über Collection
next()
hasNext:
true
next()
hasNext:
true
1324
next()
hasNext:
true
234
next()
hasNext:
true
333
next()
hasNext:
true
445
next()
hasNext:
true
54343
next()
hasNext:
true
6434
next()
hasNext:
true
75
hasNext:
false
8345
Security - 04 Cryptology
#22
Verwendung von Iteratoren
• Vorsicht: nicht 2x next() aufrufen pro 1x hasNext()
– z.B. innerhalb der while-Schleife
23
Verwendung von Iteratoren
• Oft besser: Referenz auf nächstes Objekt einer
Variable zuweisen
24
Kürzere Variante: for-Schleife
• Iterationen über Collections lassen sich mit der
for-Schleife prägnant und kurz schreiben
– Initialisierung: Zuweisung einer Iterator-Referenz
– Bedingung: Prüfen auf hasNext();
– Inkrement: Nichts tun
Security - 04 Cryptology
#25
Noch kürzere Variante: foreach-Schleife
• Seit Java 1.5 gibt es noch eine weitere Schleife
– Speziell für die Iteration über Collections, Arrays, etc.
– Abkürzende Schreibweise, kann durch for-Schleife
ersetzt werden
– Möglich für alle Objekte, die das Interface „Iterable“
implementieren
– Also z.B. Collection
• Syntax:
– for(Typ variable : iterableObject )
statement;
Security - 04 Cryptology
#26
Das Interface „Iterable“
27
Foreach und Collections
• Beispiel: Umwandlung einer for-Schleife in
eine foreach-Schleife
Security - 04 Cryptology
#28
Collections und ihre Daten
•
Beispiel
– c.add( new String(“1“) );
c.add( new Integer(42) );
•
Collection enthält String- und Integer-Instanzen
– add-Methode akzeptiert nur Object-Instanzen
– Iterator kann daher nur Object zurückgeben
•
Beispielhafte Iteration über diese Collection
– for(Object o : c)
System.out.println(“Länge: “ + ((String)o).length());
•
Problem: Typsicherheit
– Wie stellt man sicher, dass in einer Collection nur Daten eines bestimmten Typs
gespeichert werden können?
29
Wie speichert man Daten?
• class IntBox
{
private int val;
}
• class StringBox
{
private String val;
void setValue( int val )
{
this.val = val;
}
void setValue( String val )
{
this.val = val;
}
int getValue()
{
return val;
}
String getValue()
{
return val;
}
}
30
Wie implementiert man „generische“ Typen?
•
•
Häufig durch Speichern von ObjectInstanzen
•
Verwendung
– Box b = new Box();
Point p = new Point(1,2);
class ObjectBox
{
private Object val;
b.setValue( p );
((Point)b.getValue()).getX();
void setValue( Object val )
{
this.val = val;
}
•
Probleme
– Umständlich
•
Object getValue()
{
return val;
}
Jeder Zugriff erfordert Typ-Cast
– Unsicher
•
•
Typ-Cast kann fehlschlagen
((Vector)b.getValue()).doX();
ClassCastException
}
31
Lösung: Generische Typen in Java
• Sog. Java Generics
– Klassen und Methoden können „generisch“ implementiert
werden
• Statt Object wird ein Platzhalter-Typ verwendet
– Alt: private Object val;
– Neu: private T val;
• Dieser Typ kann wie ein normaler Typ verwendet werden
– Bei der konkreten Verwendung muss T spezifiert werden
Security - 04 Cryptology
Lösung: Java Generics
• class ObjectBox
{
private Object val;
}
• class Box<T>
{
private T val;
#32
Sagt Java, dass T
im Folgenden ein
Platzhalter ist
void setValue( Object val )
{
this.val = val;
}
void setValue(T val)
{
this.val = val;
}
Object getValue()
{
return val;
}
T getValue()
{
return val;
}
}
33
Verwendung
• Instanziierung
– Box<String> stringBox = new Box<String>();
– Box<Integer> intBox = new Box<Integer>();
– Box<Point> pointBox = new Box<Point>();
• Zugriff
– Point p = new Point(1,2);
pointBox.setValue( p );
double x = pointBox.getValue().getX();
getValue() liefert Point zurück
34
Generics: Einfache generische Methoden
•
class HopOderTop
{
public static <T> T aOderB(T a, T b)
{
if (Math.random() > 0.5)
return a;
else
return b;
}
}
• System.out.println(
HopOderTop.aOderB(“Zuhören“, “Weiterschlafen“)
);
• System.out.println(
“Note: “ + HopOderTop.aOderB( 1.0, 1.3 )
);
35
Seit Java 1.5 verwendet das JCF Generics
• Alt: Collection l
= new ArrayList();
• Neu: Collection<String>
= new ArrayList<String>();
• Vorteile
– Es können keine falschen Datentypen mehr gespeichert werden
– Typ-Cast entfällt
– Beispiele: nächste Folie
36
Beispiel: Ohne und mit Generics
Security - 04 Cryptology
#37
Listen
• Bisher: Collections
– Sammlung von Objekten
– Nicht notwendigerweise in einer bestimmten Reihenfolge
• Listen
– Feste Reihenfolge von Elementen
– Zugriff auf das n-te Element
• Einfügen, Löschen
• Wichtige (neue) Methoden
– get(index), remove(index), indexOf(Object), listIterator()
• Volle Referenz
– http://docs.oracle.com/javase/7/docs/api/java/util/List.html
Security - 04 Cryptology
#38
Implementierungen von java.util.List
• Vector
– Nutzt intern ein Array zur
Speicherung.
– Gibt es seit Java 1.0
• ArrayList
– Wie Vector, nur unsynchronisiert
Nur wichtig bei nebenläufigem
Zugriff
• LinkedList
– Verkettete Elemente
39
ListIterator-Interface (extends Iterator)
•
•
•
•
•
•
•
•
•
void add(E e)
boolean hasNext()
boolean hasPrevious()
E next()
int nextIndex()
E previous()
int previousIndex()
void remove()
void set(E e)
Security - 04 Cryptology
#40
ListIterator: Beispiel
• List<String> list1 =
new ArrayList<String>();
• list1.add( “Test1" );
list1.add( “Test2" );
list1.add( “Test3" );
• ListIterator<String> it =
list1.listIterator();
• System.out.println( it.next() );
System.out.println( it.previous() );
41
Verwendung von List
• List<String> list =
new ArrayList<String>();
• list.add(“Test");
list.add(0, “Test an den Anfang");
list.add(“Und hintendran");
• System.out.println(list);
• list.remove(1);
• for( String s : list )
System.out.println(“- “ + s);
42
Interne Realisierung von ArrayList
capacity = 7
size = 5
• Hat ein Array mit bestimmter Kapazität
– Speichert Größe des Arrays und
– Anzahl der gespeicherten Elemente
6
5
• Zugriff
– Schnell bei Zugriff auf bestimmte Elemente über einen Index
• Einfügen
– Kapazität verfügbar: schnelles Einfügen am Ende
Peter
4
Test
3
ein
2
ist
1
das
0
Hallo
– Kapazität erschöpft: Es wird ein neues, größeres Array
angelegt und alle Elemente kopiert Langsam
– Einfügen in der Mitte: Es werden alle darüber liegenden
Elemente um eins nach oben kopiert Langsam
Interne Realisierung von LinkedList
•
Klasse LinkedList selbst hält nur zwei Referenzen
– Auf erstes und letztes Element
•
Jedes Datenelement hat Referenz auf Vorgänger und Nachfolger
•
Einfügen an bestimmtem Index
– Suchen des n-ten Elements und einfügen durch „Umbiegen“ der Referenzen
– Besonders effizient am Anfang und am Ende
Klasse LinkedList (implementiert List)
88
Referenz auf erstes
Element
1
77
88
Referenz auf letztes
Element
9
3
1
Suchen in Listen
• Methode indexOf sucht (kleinsten) Index eines Objektes
• Beispiel
– List<Integer> list = Arrays.asList( 1, 3, 4, 1 );
– int i = list.indexOf( 1 );
– System.out.println( i );
45
Wie vergleicht man Objekte?
• Wie funktioniert der Vergleich von Objekten?
– == funktioniert nicht (vergleicht Objektreferenz)
• Zwei Interfaces in Java: Comparable, Comparator
• Eine Klasse implementiert Comparable
– Jede Instanz kann sich mit einer anderen Instanz
vergleichen
• Eine andere Klasse implementiert Comparator
– Erhält zwei Objekte und vergleicht diese miteinander
46
Comparable
• Interface java.lang.Comparable
• compareTo(T other) liefert
– < 0, wenn „this“ kleiner „other“
– > 0, wenn „this“ größer „other“
– == 0, wenn „this“ gleich „other“
47
Beispiel (ohne Sonderfälle)
public class Mensch
implements Comparable<Mensch> {
private int groesse;
public int compareTo(Mensch other) {
return groesse – other.groesse;
}
}
48
Comparator
• Interface java.util.Comparator
• Wie compareTo von java.lang.Comparable
– Vergleicht aber zwei Objekte miteinander
– Vorteil: Außerhalb der Klasse implementierbar
– Beispiel: Verschiedene Sortierstrategien
49
Beispiel: Sortieren von Collections
• Hilfsklasse java.util.Collections
– Methoden zum Sortieren von Listen
– Mit und ohne extra Comparator
• Ohne Angabe eines Comparators
– Das Comparable Interface wird verwendet
50
Beispiel: Kommandozeilenargumenten sortieren
• import java.util.*;
public class Sort {
public static void main(String[] args) {
List<String> list =
Arrays.asList(args);
Collections.sort(list);
System.out.println(list);
}
}
• Ausführen: java Das ist ein Test
• Ausgabe: [Das, Test, ein, ist]
51
Mengen in Java
• Mengen enthalten jedes Element genau einmal
– Verwenden Comparator/Comparable zur
Identitätsfeststellung
• In Java: Interface java.util.Set<T>
– Implementierungen: HashSet, TreeSet (Auswahl)
52
Beispiel für Set
• Set<String> set =
new HashSet<String>();
• set.add(“Hallo“);
set.add(“Hallo“);
set.add(“Hallo1“);
• System.out.println(
“Elemente: “ + set.size() );
• for(String s : set)
System.out.println(“Element: “ + s);
53
Stacks
• Implementierung in Java:
java.util.Stack<T>
– Erbt von Vector
– Ergänzt Funktionen eines Stacks
54
• Was fällt Ihnen auf bei dieser
Implementierung eines Stacks?
55
• Weitere wichtige Packages von Java
– java.lang.*
– java.util.*
– java.io.*
– java.net.*
56
Security - 04 Cryptology
#57
Herunterladen