14_Generics - Mobile und Verteilte Systeme

Werbung
Javakurs für Anfänger
Einheit 14: Generics
Lorenz Schauer
Lehrstuhl für Mobile und Verteilte Systeme
Heutige Agenda
Generische Klassen (Generics)
 Motivation
 Java Typ-Prüfung
 Warum also Generics?
 Generische Typen selbst definieren
 Generische Typen anwenden
Zusammenfassung
Ausblick
Praxis:
 Generische Klasse BlackBox
schreiben
Lernziele
 Einführung in generische Klassen
 Das Konzept von Generics kennenlernen und verstehen
 Generische Typen schreiben und v.a. benutzen können
09.02.2017
Javakurs 14: Generics - Lorenz Schauer
2
Motivation
Generische Typen (Generics):
 Sind ein syntaktisches Mittel für die generische Programmierung
 Zählen zu den komplexesten Typen in Java
 Seit Java 1.5 fester Bestandteil
 Grundidee: Einführung von Variablen, die Typen (statt wie bisher Werte)
speichern
 Diese Typ-Variablen repräsentieren zum Zeitpunkt der Implementierung unbekannte
Typen.
 Erst bei der Verwendung der Klassen, Schnittstellen und Methoden werden diese
Typ-Variablen durch konkrete Typen ersetzt.
 Damit kann typsichere Programmierung gewährleistet werden.
 Ein bekanntes Beispiel (hatten wir schon):
 Java.util.ArrayList<E>
 Anwendung:
ArrayList<String> meine_liste1 = new ArrayList<String>();
ArrayList<Integer> meine_liste2 = new ArrayList<Integer>();
09.02.2017
Javakurs 14: Generics - Lorenz Schauer
3
Java Typ-Prüfung
Die Typ-Prüfung passiert 2 Mal:
 Durch den Compiler (statisch)
 Führt erste Typ-Prüfung durch.
 Ist weniger „exakt“ als die dynamische Prüfung
 Durch die Laufzeitumgebung JVM (dynamisch)
 Hat absolute Typ-Intelligenz
 Prüft zur Laufzeit (als letzte Instanz), ob der Typ zum zugewiesenen Objekt passt
 Falls nicht, folgt Exception
// Beispiel:
Object o = Integer.valueOf(10);
String s = (String) o;
System.out.println(s);
Anweisungen sind für den Compiler
zunächst völlig in Ordnung.
Statische Typprüfung: korrekt
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer
cannot be cast to java.lang.String
Aber die JVM kann diese Anweisungen nicht
at Test.main(Test.java:8)
ausführen => ClassCastException
Dynamische Typprüfung: falsch!
09.02.2017
Javakurs 14: Generics - Lorenz Schauer
4
Warum also Generics?
Einführung von Generics:
 Compiler bekommt mehr Informationen über die Typen
 So sollen bspw. ClassCastExceptions vermeiden werden.
 Beispiel bei ArrayList:
Ohne parametrisierte Typen
Mit parametrisierten Typen
public static void main(String[] args) {
ArrayList myList = new ArrayList();
myList.add("Hallo");
myList.add(new Hund("Bello","Haski",98));
myList.add(new Hund("Flippo","Schaefer",101));
myList.add("Bello");
for(int i=0; i<myList.size();i++){
Hund h = (Hund) myList.get(i);
System.out.println(h.getName());
}
}
Exception in thread "main"
java.lang.ClassCastException:
java.lang.String cannot be cast to Hund
at Test.main(Test.java:15)
09.02.2017
Compiler-Fehler, da statische Typ-Prüfung
jetzt fehlschlägt!
Javakurs 14: Generics - Lorenz Schauer
5
Generische Typen deklarierten
Man kann eigene generische Typen (Klassen) definieren:
 public class MeineKlasse<T> {…}
 Objekterzeugung dann:
MeineKlasse<Typ> objektname = new MeineKlasse<Typ>();
 Bsp mit String:
MeineKlasse<String> k1 = new MeineKlasse<String>();
 Seit Java 7 auch möglich:
MeineKlasse<String> k1 = new MeineKlasse<>();
 Das T steht für den generischen Typen und kann nun als Typ-Variable in der Klasse
benutzt werden:
 Als Instanzvariable:
 Bsp.: private T meine_instanzvariable;
 Als Parameter:
 Bsp.: public MeineKlasse(T value){…}
 Als Rückgabetyp:
 Bsp.: public T doSomeStuff(){…}
Hinweis: Laut Konvention schreibt man T für Typen und E für Elemente
 Muss aber nicht sein, man kann auch <BlaDiBlub> verwenden
09.02.2017
Javakurs 14: Generics - Lorenz Schauer
6
Allgemeines Beispiel
public class MeineKlasse<T> {
Generische Klasse
Mit Typ-Variable T
// Instanzvariablen
private T instanzvariable1;
private T instanzvariable2;
private String name;
private int alter;
Generische
(parametrisierte)
Instanzvariablen
// Konstruktoren
public MeineKlasse(){
this.name = "DefaultName";
this.alter = 0;
}
public MeineKlasse(T value1, T value2){
this.instanzvariable1=value1;
this.instanzvariable1=value2;
}
public MeineKlasse(T value1, T value2, String name, int alter){
this.instanzvariable1=value1;
this.instanzvariable1=value2;
this.name = name;
this.alter = alter;
}
//Getter and Setter
public T getInstanzvariable1() {
return instanzvariable1;
}
public void setInstanzvariable1(T instanzvariable1) {
this.instanzvariable1 = instanzvariable1;
}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
}
09.02.2017
Javakurs 14: Generics - Lorenz Schauer
Nicht generische
Instanzvariablen
Konstruktor erwartet
die generischen Typen
Konstruktor erwartet
generische und nicht
generische Typen
Methode liefert
generischen Typ
zurück
Methode erwartet
generischen Typ
7
Wie wird die Klasse nun benutzt?
Ein Objekt der generischen Klasse kann nun beim Erzeugen angeben, welchen Typ
es in die Typ-Variable einsetzt.
 Analog zur ArrayList
 ArrayList<String> meineListe = new ArrayList<String>();
 ArrayList meineGenerelleListe = new ArrayList();
 Wird kein Typ angegeben wird implizit die Super-Klasse Object eingesetzt
 D.h.: Dann weiß der Compiler genauso wenig über die „echten“ Typen wie zuvor und
man muss auf Typ-Casting zurückgreifen!
 Das ist nicht der Sinn von Generics und wird mit einer Compiler-Warnung bestraft:
“ArrayList is a raw type. References to generic type ArrayList<E> should be
parameterized“
09.02.2017
Javakurs 14: Generics - Lorenz Schauer
8
Wie wird die Klasse nun benutzt?
public class Test{
objekt1 legt keinen generischen
Typ fest.
=> Es wird implizit Object
verwendet
public static void main(String[] args) {
// Objekt erzeugen:
MeineKlasse objekt1 = new MeineKlasse();
MeineKlasse<String> objekt2=new MeineKlasse<>();
objekt2 setzt String
MeineKlasse<Integer> objekt3=new MeineKlasse<>(); objekt3 setzt Integer
objekt1 setzt Instanzvariable1
// Methoden-Aufrufe
auf „Peter“.
objekt1.setInstanzvariable1("Peter");
String s1 =(String)objekt1.getInstanzvariable1(); Korrekt, da generischer Typ =
Object
objekt2.setInstanzvariable1("Maria");
Bei Nutzung Typ-Cast nötig!
String s2 = objekt2.getInstanzvariable1();
objekt3.setInstanzvariable1(23);
int s3 = objekt3.getInstanzvariable1();
}
}
09.02.2017
objekt2 setzt Instanzvariable1 auf
„Maria“
Korrekt, da generischer Typ = String
objekt3 setzt Instanzvariable1 auf 23
Korrekt, da generischer Typ = int
Javakurs 14: Generics - Lorenz Schauer
9
Generische Typen einschränken
Manchmal ist der bloße Typ <T> zu generisch und man möchte die akzeptierten
Möglichkeiten einschränken:
 Mittels <T extends ClassOrInterface> lässt sich ein Typ bestimmen der
eine bestimmte Klasse erweitert oder ein Interface implementiert
 Bsp.:
 public class MeineKlasse <T extends CharSequence> {…}
 Die Erzeugung mittels new MeineKlasse<String>(); ist demnach erlaubt
 Eine Erzeugung mit new MeineKlasse<Integer>(); verbietet der Compiler
- Bound mismatch: The type Integer is not a valid substitute for
the bounded parameter <T extends CharSequence> of the type
MeineKLasse<T>
 Soll <T> zu mehreren Typen passen, kann man mittels & noch weitere Interfaces
hinzufügen
 Bsp.: public class MeineKlasse <T extends CharSequence & Comparable>
09.02.2017
Javakurs 14: Generics - Lorenz Schauer
10
Programmieraufgabe zu Generics
Schreiben Sie in Analogie zur ArrayList eine generische Klasse BlackBox<E> welche folgende
Methoden anbieten soll:
 add(E element) fügt ein Element Ihrer Box hinzu
 remove(E element) löscht ein Element aus Ihrer Box
 clear() löscht alle Element aus Ihrer Box
 getElementAtPosition(int i) liefert das Element an der Position i zurück
 printNamesOfElements() gibt die Namen sämtlicher Elemente in der BlackBox auf der
Konsole aus
 Hinweis: Nutzen Sie hierfür die Methode toString(), welche von der Oberklasse Object
bereitgestellt wird.
Zusätzlich soll die Klasse folgende Attribute bereitstellen
 String name (welcher über den Konstruktor gesetzt wird)
 Eine geeignete Datenstruktur zum Speichern der Elemente
 Hinweis: Der Einfachheit halber nutzen Sie hier die ArrayList<E>, mit der Sie oben genannte
Methoden leicht implementieren können.
Nutzen Sie nun Ihre neue Klasse BlackBox und erzeugen Sie 2 Instanzen mit unterschiedlichen
Typen.
 Sie können auf Klassen von vorangegangenen Stunden zurückgreifen (Hund, Auto)
Erzeugen Sie nun mehrere Objekte der beiden gewählten Klassen und fügen Sie diese in die
entsprechene BlackBox ein.
Was erscheint auf der Konsole, wenn Sie die printNamesOfElements() Methode auf den
beiden BlackBox Objekten aufrufen?
09.02.2017
Javakurs 14: Generics - Lorenz Schauer
11
Zusammenfassung
Sie haben nun die grundlegenden Elemente der objektorientierten
Programmiersprache Java kennengelernt:
 Klassen, Objekte, Variablen & Methoden
 Zusammenspiel verschiedener Klassen und Objekte
 Abstraktion und Datenkapselung
 Kontrollstrukturen
 Statische und dynamische Arrays
 Vererbung
 Subtyping, Typ-Casting, …
 Abstrakte Klassen
 Interfaces
 Anonyme innere Klassen





Polymorphismus
Exceptions
Generics
UML
Java API Dokumentation
09.02.2017
Javakurs 14: Generics - Lorenz Schauer
12
Und jetzt…?
Fortführende Themen wären:
 Weitere Datenstrukturen
 (verkettete) Listen, Stack, Schlangen (Queues), Hash-Tables, Bäume (Trees)
 Frameworks
 Collection-Framework
 Nebenläufigkeit
 Threads, Conditions, Synchronisation, Monitore
 GUI-Programmierung mit Swing / JavaFX
 Design-Pattern
 Algorithmen
 Sortieren & Suchen, Rekursion, …
 U.v.m.
 Einfach am Ball bleiben und viel programmieren ;)
 Den Java-Kurs für Fortgeschrittene im nächsten Semester besuchen…
09.02.2017
Javakurs 14: Generics - Lorenz Schauer
13
Vielen Dank!
Vielen Dank
fürs Zuhören und Mitmachen!
09.02.2017
Javakurs 14: Generics - Lorenz Schauer
14
Herunterladen