Java - von am Wednesday, December 5, 2007 23:18 - 1 Kommentar

Java Generics – Generische Methoden, Klassen und Interfaces

Generics wurden mit Java 5, dem Tiger-Release, eingeführt und stellen gegenüber Java 1.4 eine erhebliche Arbeitserleichterung dar. Ich möchte Sie in das Thema Generics, anhand der Klasse ArrayList, einführen. Wir werden sehen, welche Probleme es seither beim Ein- und Auslesen von Elementen bei der ArrayList gab und wie sie durch die Einführung von Generics gelöst wurden. Anhand des Comparable Interface möchte ich Ihnen außerdem zeigen, wie generische Methoden, Interfaces und Klassen formuliert werden können.

Wenn Sie tiefer in die Generics einsteigen, und auch andere fortgeschrittene Programmiertechniken kennenlernen möchten, werfen Sie einen Blick auf Fortgeschrittene Programmierung mit Java 5: Generics, Annotations, Concurrency und Reflection von Johannes Nowak. Das Buch geht auf den ersten 150 Seiten detailliert – und dank zahlreicher Beispiele sehr verständlich – auf die Generics in Java ein und ist sehr lesenswert.

Die ArrayList

Planen Sie umzuziehen und brauchen Umzugskartons, einen neuen Teppich und neue Lampen? So erstellen Sie eine Liste. Eine Liste, die alle wichtigen Dinge enthält, die Sie für einen erfolgreichen Umzug brauchen. Wollen Sie eine Liste in Java erstellen, so gibt es drei Möglichkeiten: die Klassen LinkedList, Vector und ArrayList, die alle drei das Interface List implementieren und sich im Package java.util befinden. Wir wollen uns auf Objekte der Klasse ArrayList konzentrieren, da es die beste Implementierung aller Listen darstellt und einen indexierten und sehr schnellen wahlfreien Zugriff hat. Die Elemente der ArrayList werden in gleicher Reihenfolge ausgelesen, wie sie eingegeben wurden. Listen in Java haben wie Arrays einen Index und ein Feld.

Indexposition   Element
      0         String karton = new String("Karton");
      1         String teppich = new String("Teppich");
      2         String lampen = new String("Lampen");

Wie werden der ArrayList Elemente hinzugefügt? Mit der Methode add(). Und wie werden die Elemente wieder aus der ArrayList entfernt? Mit der Methode remove().

Die Methoden der Klasse Iterator machen es Ihnen möglich, Elemente aus der ArrayList auszulesen. Die Methode iterator() liest alle Elemente aus, die Methode hasNext() stellt fest, ob die ArrayList noch weitere Elemente enthält und die Methode next() liest die einzelnen Elemente aus. Wenden wir diese Methoden an, wird uns ein Fehler angezeigt und starten wir die Klasse, wird uns gesagt, dass ein Objekt der Klasse Object gefunden wurde und kein Objekt der Klasse String. Wie seltsam! Wir fügen der ArrayList Objekte der Klasse String hinzu und erhalten aber als Ausgabe Objekte der Klasse Object.

Screenshot: Java Generics - Generische Methoden, Klassen und Interfaces

Wie können Sie diese Fehlermeldung verhindern? Durch einen Cast, sprich das Objekt der Klasse Object muss in ein Objekt der Klasse String zurückgewandelt werden. So muss unsere abgewandelte Klasse Umzug mit Cast wie folgt lauten:

  1. package Beispiele;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.Iterator;
  5.  
  6. public class Umzug {
  7.    
  8.     public static void main(String[ ] args){
  9.    
  10.     ArrayList umzugsListe = new ArrayList();
  11.     umzugsListe.add("Karton");
  12.     umzugsListe.add("Teppich");
  13.     umzugsListe.add("Lampen");
  14.    
  15.     for(Iterator i = umzugsListe.iterator(); i.hasNext();){
  16.         String s = (String)i.next();
  17.         System.out.println(s);
  18.     }  
  19.    
  20.     }
  21. }

Kompliziert, oder nicht? Dies dachten sich die Entwickler bei Sun auch und sie machten sich Gedanken über eine Lösung, die mit dem Tiger-Release eingeführt wurde. Die Lösung heißt: generische ArrayListen.

Was ist eine generische ArrayList?

Eine generische ArrayList erlaubt es Ihnen genau zu definieren, welche Elemente einer ArrayList hinzugefügt werden dürfen und welche wieder ausgelesen werden. Ergänzen Sie beim Instanziieren die ArrayList um können dieser ArrayList nur Strings hinzugefügt werden und außerdem werden auch nur Strings wieder ausgegeben. Die vollständige Befehlszeile lautet:

  1. ArrayList<String> umzugsListe = new ArrayList<String>();

Wollen Sie die generische ArrayList wieder mit Methoden der Klasse Iterator auslesen, haben Sie wieder das gleiche Problem. Mit dem Iterator wird nach wie vor ein Objekt der Klasse Object ausgegeben und kein Objekt der Klasse String. Um dieses Problem zu lösen, wurde gleichzeitig eine neue for-Schleife eingeführt, die sogenannte erweiterte for-Schleife. Das String s: umzugsListe in der Klammer der unten stehenden for-Schleife liest bei jedem Schleifendurchlauf ein Element der ArrayList aus und speichert es in der Variablen s.

  1. package Beispiele;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.Iterator;
  5.  
  6. public class UmzugGenerisch {
  7.    
  8.    public static void main(String[] args){
  9.    
  10.         /*Einer generischen ArrayList<String> können nur Objekte
  11.      der Klasse String hinzugefügt werden.*/
  12.     ArrayList<String> umzugsListe = new ArrayList<String>();
  13.     umzugsListe.add("Karton");
  14.     umzugsListe.add("Teppich");
  15.     umzugsListe.add("Lampen");
  16.    
  17.    
  18.     /*Die erweiterte for-Schleife erlaubt es Ihnen direkt
  19.      den Inhalt der ArrayList auszulesen, wobei s vom gleichen
  20.      Typ sein muss, wie die Elemente der ArrayList.*/
  21.     for(String s: umzugsListe){  
  22.         System.out.println(s);
  23.     }  
  24.     }  
  25. }

Ausgabe:

Karton
Teppich
Lampen

Kein Cast ist mehr nötig und die Methoden der Klasse Iterator sind durch die erweiterte for-Schleife ersetzt worden und die Reihenfolge der Ausgabe entspricht der Reihenfolge der Eingabe.

Werden einer generischen ArrayList Objekte einer bestimmten Klasse übergeben und erhalten Sie Objekte dieser gleichen Klasse als Ausgabe zurück, so nennt man dies Typsicherheit. Es wird sichergestellt, dass Sie immer den gleichen Typ zurückbekommen.

Generische Methoden, Klassen und Interfaces

Kann man auch bei Methoden, Klassen und Interfaces Typsicherheit gewährleisten? Ja! Sie übergeben der Methode, Klasse oder dem Interface einen bestimmten Typ als Parameter. Dies werden wir anhand des Comparable Interface uns näher ansehen. Wozu brauche ich das Comparable Interface? Zum Sortieren von Elementen innerhalb einer ArrayList. Wollen Sie Objekte einer Klasse auf- oder absteigend sortieren, muss diese Klasse das Comparable Interface implementieren. Bei der Klasse String ist dies bereits der Fall. Alles was Sie jetzt noch brauchen ist die statische Methode sort(List list) und reverse(List list) der Klasse Collections des Package java.lang. Wobei das für einen bestimmten Typ als Parameter steht und die Methode sort() aufsteigend sortiert und die Methode reverse() absteigend. Und schon wird die Ausgabe alphabetisch auf- und absteigend sortiert:

  1. package Beispiele;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.Collections;
  5.  
  6. public class StringSortieren {
  7.    
  8.     public static void main(String[ ] args){
  9.    
  10.     ArrayList<String> umzugsListe = new ArrayList<String>();
  11.     umzugsListe.add("Karton");
  12.     umzugsListe.add("Teppich");
  13.     umzugsListe.add("Lampen");
  14.    
  15.     /*Die statische Methode sort() sortiert die Elemente
  16.      aufsteigend.*/
  17.     Collections.sort(umzugsListe);
  18.    
  19.     for(String s: umzugsListe){
  20.         System.out.println("Aufsteigend: " + s);
  21.     }
  22.    
  23.     /*Die statische Methode reverse() sortiert die Elemente
  24.      absteigend.*/
  25.     Collections.reverse(umzugsListe);
  26.    
  27.     for(String s: umzugsListe){
  28.         System.out.println("Absteigend: " + s);
  29.     }
  30.     }
  31. }

Ausgabe:

Aufsteigend: Karton
Aufsteigend: Lampen
Aufsteigend: Teppich
Absteigend: Teppich
Absteigend: Lampen
Absteigend: Karton

Wie implementiere ich das Interface Comparable?

Für alle anderen Klassen bleibt jetzt die Frage: Wie implementieren wir das Interface Comparable? Das Interface Comparable besitzt eine Methode compareTo(T o), die implementiert werden muss. In den alten Java-Versionen wurde dieser Methode ein Objekt übergeben, das anschließend gecastet, sprich wieder in das ursprüngliche Objekt zurückgewandelt, werden musste. Nun können Sie dieser Methode einen bestimmten Typ übergeben und erhalten so auch den gleichen Typ zurück.

  1. package Beispiele;
  2.  
  3. /*Sie implementieren das generische Comparable-Interface*/
  4. public class Utensilien implements Comparable<Utensilien>{
  5.    
  6.     private String name;
  7.    
  8.     public Utensilien (String name){
  9.     this.name = name;
  10.     }
  11.    
  12.     public String getName() {
  13.     return name;
  14.     }
  15.    
  16.     public void setName(String name) {
  17.     this.name = name;
  18.     }
  19.    
  20.     /*Der Methode compareTo(Utensilien) können Sie nur
  21.      noch Objekte der Klasse Utensilien übergeben.*/
  22.     public int compareTo(Utensilien u) {
  23.    
  24.     /*Die Namen der Objekte der Klasse Utensilien werden
  25.      miteinander verglichen und der Cast
  26.      ((Utensilien)u).getName() ist nicht mehr nötig.*/
  27.     return name.compareTo(u.getName());
  28.     }  
  29. }

Für alle die es gewohnt waren Objekte casten zu müssen, ist dies sicherlich eine enorme Arbeitserleichterung.

Nachdem das Comparable Interface implemtiert wurde, können Sie jetzt Objekte der Klasse Utensilien der generischen ArrayList hinzufügen und sofort die Methode sort() anwenden.

  1. package Beispiele;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.Collections;
  5.  
  6. public class UmzugUtensilien {
  7.    
  8.      public static void main(String[] args){
  9.    
  10.     ArrayList<Utensilien> umzugsListe = new ArrayList<Utensilien>();
  11.     Utensilien u = new Utensilien("Karton");
  12.     Utensilien u1 = new Utensilien("Teppich");
  13.     Utensilien u2 = new Utensilien("Lampen");
  14.    
  15.     umzugsListe.add(u);
  16.     umzugsListe.add(u1);
  17.     umzugsListe.add(u2);
  18.    
  19.     Collections.sort(umzugsListe);
  20.    
  21.     for(Utensilien utensilien: umzugsListe){
  22.         System.out.println("Utensilien: " + utensilien.getName());
  23.     }
  24.    
  25.     }
  26. }

Ausgabe:

Utensilien:Karton
Utensilien: Lampen
Utensilien: Teppich

Generics als Thema für die Java-Zertifizierung

Das Thema Generics gehört zu den Prüfungsthemen des Sun Certified Java Programmer (SCJP). Dieses Java-Zertifikat umfasst Grundlagenthemen, wie z.B. Enums, Threads, Varargs, Exceptions, Garbage Collection, Kontrollstrukturen, Arrays, Standardklassen, Grundlagen der Objektorientierung, primitive Datentypen und Ein- und Ausgabe von Datenströmen. Unten stehend finden Sie einige Links zu Materialien. Für alle die sich sehr gute Java-Grundlagen erarbeiten möchten, stellt diese Prüfung eine hervorragende Leistungskontrolle dar. Und in allen Büchern zum Thema finden Sie hervorragende Einführungen in Java.

Sourcecode zum Artikel

Sourcecode: Java Generics

Weiterführende Literatur und zusätzliche Informationsquellen:

Suchen Sie leicht verständliche Erläuterungen für die Java-Grundlagen, dann sind Sie bei Bert Bates und Kathy Sierra und dem Buch “Java von Kopf bis Fuß” gut aufgehoben. Dieses Buch ist besonders für Anfänger geeignet.

Eine ausführliche Einführung in alle Themen zum Sun Certified Java Programmer finden Sie auch in dem Buch “SCJP Sun Certified Programmer for Java 5 Study Guide” ebenfalls von Bert Bates und Kathy Sierra.

Vielleicht eines der besten Java-Bücher überhaupt, aber bisher leider nur für 1.4 erhältlich, ist das englische Buch von Khalid A. Mughal und Rolf W. Rasmussen “A Programmer’s Guide to Java Certification: A Comprehensive Primer“.

Wollen Sie sich einen kurzen Überblick über die Neuerungen des Tiger-Releases verschaffen, so wird Ihnen das Buch “Java 1.5 Tiger. A Developer’s Notebook” von David Flanagan und Brett McLaughlin von großem Nutzen sein.

Wenn Sie sich gerne in die Java-Grundlagen, die Themen der Java-Zertifizierung sind, einarbeiten möchten und Wert auf einfache und ausführliche Erklärungen legen, könnte Sie mein Buch interessieren: “Das große SCJP-Trainingsbuch“.

Sollten Sie Fragen zu allen Java-Zertifizierungen haben, ist das englischsprachige Forum Javaranch die erste Adresse.

Liegt es Ihnen mehr, sich mit einem Simulationssoftware für Zertifizierungen vorzubereiten, so könnte Sie die Software von Whizlabs etwas für Sie sein.

Nähere Informationen zum Sun Certified Java Programmer erhalten Sie auch direkt bei Sun.

Be Sociable, Share!


Kommentare

Kommentieren

Weitere Empfehlungen: