From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001
From: Sven Eisenhauer
+
+Dieser Abschnitt beschreibt eine Erweiterung, die seit der J2SE 5.0
+zur Verfügung steht und unter dem Namen »Generics«
+bekannt geworden ist. Es geht dabei vordergründig um die Möglichkeit,
+typsichere Collection-Klassen zu definieren. Also solche, in die nicht
+nur allgemein Objekte des Typs Object
+gesteckt werden können, sondern die durch vorhergehende Typisierung
+sicherstellen, dass nur Objekte des korrekten Typs (etwa Integer
+oder String)
+eingefügt werden können. Diese, von vielen Java-Entwicklern
+seit langer Zeit geforderte, Spracherweiterung bringt zwei wichtige
+Vorteile:
+
+
+Genau genommen geht es nicht nur um Collections im eigentlichen Sinne,
+sondern um die Typisierung von beliebigen Java-Klassen. Also die Möglichkeit,
+festzulegen, dass eine bestimmte Klasse X
+zwar so implementiert wurde, dass sie prinzipiell mit allen
+anderen Klassen zusammen arbeitet (bzw. Objekte deren Typs aufnimmt),
+im konkreten Anwendungsfall von X
+aber die Möglichkeit besteht, die Zusammenarbeit (etwa aus Sicherheits-
+oder Konsistenzgründen) auf eine fest vorgegebene andere Klasse
+zu beschränken.
+Was sich etwas kompliziert anhört, wollen wir durch ein einfaches
+Beispiel illustrieren:
+
+
+
+
+
+
+ Titel
+ Inhalt
+ Suchen
+ Index
+ DOC
+ Handbuch der Java-Programmierung, 5. Auflage
+
+ <<
+ <
+ >
+ >>
+ API
+ Kapitel 15 - Collections II
+
+
+
+
+
+15.8 Typisierte Klassen und generische Collections
+
+
+
+
+
+
+
+
+15.8.1 Grundlagen
+
+
+
+
+
+
+![]()
+
+![]()
+
+
+
+
+
+![]()
+
+
+
+
+
+ JDK1.1-6.0
+
+
+
+
+
+
+
+
+![]()
+
+
+
+![]()
+
+
+
+
+
+ Hinweis
+
+
+
+
+Listing 15.8: Eine untypisierte Sortiermethode
+
+
+
+
+
+001 public static void printSorted1(int... args)
+002 {
+003 Vector v = new Vector();
+004 for (int i = 0; i < args.length; ++i) {
+005 v.addElement(new Integer(args[i]));
+006 }
+007 Collections.sort(v);
+008 for (int i = 0; i < v.size(); ++i) {
+009 int wert = 10 * ((Integer)v.elementAt(i)).intValue();
+010 System.out.print(wert + " ");
+011 }
+012 System.out.println();
+013 }
+
+
+printSorted1 bekommt als Parameter +eine Menge von Ganzzahlen übergeben und hat die Aufgabe, diese +mit 10 zu multiplizieren und sortiert auf der Konsole auszugeben. +Die Methode legt dazu einen Vector v +an und fügt in diesen zunächst die in Integer +konvertierten int-Werte +ein. Anschließend sortiert sie den Vector, liest die Integer-Objekte +aus, konvertiert sie in int-Werte +zurück und gibt die mit 10 multiplizierten Ergebnisse auf der +Konsole aus. + +
+Seit der J2SE 5.0 kann die Methode nun typsicher gemacht werden: + + +
+
+
+
+001 public static void printSorted2(int... args)
+002 {
+003 Vector<Integer> v = new Vector<Integer>();
+004 for (int i = 0; i < args.length; ++i) {
+005 v.addElement(new Integer(args[i]));
+006 }
+007 Collections.sort(v);
+008 for (int i = 0; i < v.size(); ++i) {
+009 int wert = 10 * v.elementAt(i).intValue();
+010 System.out.print(wert + " ");
+011 }
+012 System.out.println();
+013 }
+
+ |
+
+Der Vector
+wurde hier mit einem Typ-Parameter versehen, der in spitzen Klammern
+angegeben wird:
+
+
+Vector<Integer> v = new Vector<Integer>();
+
+
+
+
+Dadurch wird dem Compiler mitgeteilt, dass dieser Vector +ausschließlich Integer-Objekte +aufnehmen kann. Alle Versuche, darin einen String, +ein Double +oder irgendein anderes Nicht-Integer-Objekt zu speichern, werden vom +Compiler unterbunden. Auch der zweite der oben genannten Vorteile +kommt zum Tragen: beim Zugriff auf Vector-Elemente +mit Hilfe der Methode elementAt +werden diese automatisch in ein Integer +konvertiert, der übliche Typecast kann also entfallen. + +
+Auf diese Weise können nun seit der J2SE 5.0 alle Collection-Klassen +typsicher verwendet werden: einfach den Datentyp in spitzen Klammern +direkt hinter dem Klassennamen angeben! Auch bei Collections, die +mit mehr als einem Parameter arbeiten, ist das möglich, also +inbesondere bei den verschiedenen Maps. Hier werden beide Parameter +in spitzen Klammern angegeben und durch Kommata voneinander getrennt. +Wir werden dazu später ein Beispiel sehen. + +
+Zunächst soll jedoch das obige Beispiel weiter vereinfacht werden. +Tatsächlich ist printSorted2 +nämlich etwas länger als printSorted1, +d.h. wir haben uns die Typsicherheit durch zusätzlichen +Code erkauft. Daß es wesentlich einfacher geht, zeigt folgende +Variante: + + +
+
+Hier kommen zusätzlich folgende Techniken zum Einsatz: +
+Dieses Programm sieht wesentlich besser aus als die erste Fassung. +Es ist nun sowohl typsicher als auch besser lesbar. Möglich gemacht +wird dies durch verschiedene Neuerungen der J2SE 5.0, die hier im +Zusammenspiel ihr Synergiepotential entfalten. Autoboxing und Autounboxing +werden in Abschnitt 10.2.3 erläutert +und die erweiterte for-Schleife +in Abschnitt 6.3.3. Auch +die variablen Parameterlisten sind eine Neuerung der J2SE 5.0; sie +werden in Abschnitt 7.3.4 +erläutert. + + + + +
+Wie bereits erwähnt können auch Collections typsicher gemacht
+werden, deren Methoden üblicherweise mehr als einen Parameter
+erwarten. Ein gutes Beispiel dafür ist das Interface Map
+und dessen implementierende Klassen (etwa HashMap,
+TreeMap
+oder Hashtable).
+Sie speichern nicht einzelne Werte, sondern Schlüssel-Wert-Paare.
+Soll eine solche Klasse typsicher verwendet werden, sind bei der Deklaration
+zwei Typ-Parameter anzugeben:
+
+
+Hashtable<String, Integer> h = new Hashtable<String, Integer>();
+
+
+
+
+An die Einfügeoperationen, die beide Parameter erwarten, muss +nach einer solchen Deklaration zwangsweise ein String und ein Integer +übergeben werden. Die Zugriffsmethoden dagegen erwarten einen +String +als Schlüssel und liefern einen Integer +als Rückgabewert. Beispielhaft wollen wir uns eine Methode ansehen, +die eine Liste von Strings erwartet und dann zählt, wie oft jedes +einzelne Wort darin vorkommt. Eine Pre-5.0-Implementierung könnte +so aussehen: + + +
+
+
+
+001 public static void wordCount1(String[] args)
+002 {
+003 Hashtable h = new Hashtable();
+004 for (int i = 0; i < args.length; ++i) {
+005 int cnt = 1;
+006 if (h.containsKey(args[i])) {
+007 cnt = 1 + ((Integer)h.get(args[i])).intValue();
+008 }
+009 h.put(args[i], new Integer(cnt));
+010 }
+011 System.out.println(h);
+012 }
+
+ |
+
+Für jedes Element des Parameter-Arrays wird geprüft, ob +es schon in der Hashtable +h enthalten ist. Ist das der +Fall, wird das Wort als Schlüssel verwendet, der zugehörige +Zählerstand aus h gelesen +und um 1 erhöht. Ist das nicht der Fall, wird der Zähler +mit 1 initialisiert. Anschließend wird der Zählerwert mit +dem Wort als Schlüssel in die Hashtable geschrieben. + +
+Seit der J2SE 5.0 kann man die Methode stark vereinfachen: + + +
+
+
+
+001 public static void wordCount2(String... args)
+002 {
+003 Hashtable<String, Integer> h = new Hashtable<String, Integer>();
+004 for (String key : args) {
+005 if (h.containsKey(key)) {
+006 h.put(key, 1 + h.get(key));
+007 } else {
+008 h.put(key, 1);
+009 }
+010 }
+011 System.out.println(h);
+012 }
+
+ |
+
+Auch hier machen wir uns gleich alle drei oben genannten Erweiterungen +der J2SE 5.0 zu Nutze. Zudem gibt es einen weiteren Vorteil. Da nun +die Datentypen der Methoden put +und get +bekannt sind, können wir - dank der Verkürzung durch Autoboxing +und Autounboxing - die Programmstruktur übersichtlicher machen. +Wir schreiben dazu die put- +und get-Operationen +in eine Zeile, die Hilfsvariable cnt +wird gar nicht mehr gebraucht. + + + + +
+Nachdem wir uns in den vorherigen Abschnitten angesehen haben, wie +generische Collections verwendet werden, wollen wir nun eine eigene +generische Listenklasse implementieren. Deren Interface soll bewußt +schlank gehalten werden, um unnötige Verkomplizierungen zu vermeiden. +Es besteht aus je einer Methode, um Elemente einzufügen und auszulesen, +einer Methode zur Abfrage der Größe und aus einem Iterator, +um die Elemente (u.a. mit den neuen foreach-Schleifen der J2SE 5.0) +durchlaufen zu können. + +
+Der Einfachheit halber wollen wir die Liste mit einem Array als interne +Datenstruktur realisieren und definieren dazu folgende Klasse: + + +
+
+
+
+001 import java.util.*;
+002
+003 /**
+004 * Die folgende Klasse realisiert eine einfache Liste mit einer
+005 * festen Größe. Die Liste kann typisiert werden, so dass
+006 * Zugriffs- und Hinzufügemethoden typsicher werden. Darüber
+007 * hinaus implementiert sie das Interface Iterable und stellt
+008 * einen typsicheren Iterator zur Verfügung, um die Verwendung
+009 * in J2SE-5.0-foreach-Schleifen zu ermöglichen.
+010 */
+011 public class MiniListe<E>
+012 implements Iterable<E>
+013 {
+014 private Object[] data;
+015 private int size;
+016
+017 /**
+018 * Erzeugt eine leere Liste, die maximal maxSize Elemente
+019 * aufnehmen kann.
+020 */
+021 public MiniListe(int maxSize)
+022 {
+023 this.data = new Object[maxSize];
+024 this.size = 0;
+025 }
+026
+027 /**
+028 * Fügt ein Element zur Liste hinzu. Falls diese schon
+029 * voll ist, wird eine Exception ausgelöst.
+030 */
+031 public void addElement(E element)
+032 {
+033 if (size >= data.length) {
+034 throw new ArrayIndexOutOfBoundsException();
+035 }
+036 data[size++] = element;
+037 }
+038
+039 /**
+040 * Liefert die Anzahl der Elemente in der Liste.
+041 */
+042 public int size()
+043 {
+044 return size;
+045 }
+046
+047 /**
+048 * Liefert das Element an Position pos. Falls kein solches
+049 * Element vorhanden ist, wird eine Exception ausgelöst.
+050 */
+051 public E elementAt(int pos)
+052 {
+053 if (pos >= size) {
+054 throw new NoSuchElementException();
+055 }
+056 return (E)data[pos];
+057 }
+058
+059 /**
+060 * Liefert einen Iterator zum Durchlaufen der Elemente.
+061 */
+062 public Iterator<E> iterator()
+063 {
+064 return new Iterator<E>()
+065 {
+066 int pos = 0;
+067
+068 public boolean hasNext()
+069 {
+070 return pos < size;
+071 }
+072 public E next()
+073 {
+074 if (pos >= size) {
+075 throw new NoSuchElementException();
+076 }
+077 return (E)data[pos++];
+078 }
+079 public void remove()
+080 {
+081 throw new UnsupportedOperationException();
+082 }
+083 };
+084 }
+085
+086 //------------------------------------------
+087 public static void main(String[] args)
+088 {
+089 //Untypisierte Verwendung
+090 MiniListe l1 = new MiniListe(10);
+091 l1.addElement(3.14);
+092 l1.addElement("world");
+093 for (Object o : l1) {
+094 System.out.println(o);
+095 }
+096 //Ganzzahlige Typisierung
+097 System.out.println("---");
+098 MiniListe<Integer> l2 = new MiniListe<Integer>(5);
+099 l2.addElement(3);
+100 l2.addElement(1);
+101 l2.addElement(4);
+102 for (Integer i : l2) {
+103 System.out.println(i + 1000);
+104 }
+105 //Verwendung read-only
+106 System.out.println("---");
+107 MiniListe<? extends Number> l3 = l2;
+108 for (Number i : l3) {
+109 System.out.println(i.intValue() + 1000);
+110 }
+111 }
+112 }
+
+ |
++MiniListe.java | +
+Die Ausgabe des Programms ist:
+
+
+3.14
+world
+---
+1003
+1001
+1004
+---
+1003
+1001
+1004
+
+
+
+
+Wir wollen uns einige interessante Implementierungsdetails ansehen: +
+ public void addElement(Integer element) + ++ +
+Damit ist die komplette Schnittstelle der Klasse typsicher, und wir +können sie wie in den vorigen Abschnitten beschrieben verwenden. +Die main-Methode +zeigt einige Anwendungen, die nach den bisherigen Ausführungen +selbsterklärend sein sollten. +
+
![]() |
+![]() |
+
+
+
+Zu beachten ist, dass in diesem Beispiel »nur« die öffentliche
+Schnittstelle der Klasse typsicher ist. Innerhalb der Klasse selbst
+ist es nach wie vor möglich, fehlerhaft typisierte Werte in das
+Datenarray einzufügen, denn als Object[]
+kann es beliebige Objekte aufnehmen. Wir könnten eine solche
+Schnittstelle sogar öffentlich machen:
+
+ +Dieser Code wäre vollkommen korrekt und würde vom Compiler +nicht beanstandet werden. Ein Aufruf der Methode in einer MiniListe<Double> +würde tatsächlich einen String +einfügen, und beim Zugriff auf dieses Element würde es zu +einer ClassCastException +kommen. »Typsichere« Klassen sind also nur dann wirklich +typsicher, wenn die Implementierung sicherstellt, dass keine typfremden +Werte gespeichert werden. |
+
+
|
+![]() |
+
+Beim Umgang mit typisierten Collections gibt es einige Besonderheiten, +die zu einer Verkomplizierung des ursprünglichen Mechanismus +geführt haben. Wir wollen zunächst eine einfache Methode +betrachten, um uns noch einmal das Zusammenspiel zwischen Ober- und +Unterklassen anzusehen (es wurde unter dem Stichwort »Polymorphismus« +bereits in den Abschnitten Abschnitt 7.1.6 +und Abschnitt 8.4 erläutert): + + +
+
+
+
+001 public static void doesWork1()
+002 {
+003 Double pi = new Double(3.14);
+004 Number num = pi;
+005 System.out.println(num.toString());
+006 Double pi2 = (Double)num;
+007 }
+
+ |
+
+Zunächst wird eine Double-Variable +pi angelegt und mit dem Fließkommawert +3.14 initialisiert. In der nächsten Zeile machen wir uns die +Tatsache zunutze, dass Double +eine Unterklasse von Number +ist und weisen der Variablen der Oberklasse einen Wert der Unterklasse +zu. Dies entspricht unserem bisherigen Verständnis von objektorientierter +Programmierung, denn ein Double +ist eine Number, +hat alle Eigenschaften von Number +(und ein paar mehr), und kann daher problemlos als Number +verwendet werden. Die nächsten beiden Zeilen beweisen, dass diese +Annahme korrekt ist (der Inhalt von num +ist tatsächlich 3.14) und dass man die Number-Variable +auch zurückkonvertieren kann - in Wirklichkeit zeigt sie ja auf +ein Double. +
+
![]() |
+![]() |
+
+
+
+Überträgt man das Beispiel auf typisierte Collections, lassen
+sich die dahinter stehenden Annahmen nicht ohne weiteres aufrecht
+erhalten. Ein Vector<Double>
+ist kein Subtyp eines Vector<Number>!
+Die folgenden Codezeilen sind illegal und werden vom Compiler abgewiesen:
+
+ |
+
+
|
+![]() |
+
+Wir wollen uns ansehen, warum das so ist. Wären sie nämlich +erlaubt, könnten wir folgende Methode schreiben: + + +
+
+
+
+001 public static void doesntWork1()
+002 {
+003 Vector<Double> vd = new Vector<Double>();
+004 Vector<Number> vn = vd;
+005 vn.addElement(new Integer(7));
+006 Double x = vd.elementAt(0);
+007 }
+
+ |
+
+Das Programm erzeugt einen Vector<Double> +vd und weist ihn einer Vector<Number>-Variable +vn zu. Wäre diese eine Oberklasse von Vector<Double>, +könnten wir natürlich auch Integer-Werte +in den Vector +einfügen wollen. Denn auch Integer +ist eine Unterklasse von Number, +und mit derselben Berechtigung würden wir annehmen, dass Vector<Number> +Oberklasse von Vector<Integer> +ist. Dann wäre aber nicht mehr sichergestellt, dass beim Zugriff +auf vd nur noch Double-Elemente +geliefert werden, denn über den Umweg vn +haben wir ja auch ein Integer-Objekt +eingefügt. Der Compiler könnte also nicht mehr garantieren, +dass die vierte Zeile korrekt ausgeführt wird. + +
+Daraus ist ein folgenschwerer Schluß zu ziehen: Ist U +eine Unterklasse von O, so folgt +daraus eben nicht, dass auch G<U> +eine Unterklasse von G<O> +ist. Das ist schwer zu verstehen, denn es widerspricht unseren bisherigen +Erfahrungen im Umgang mit Ober- und Unterklassen. Das Problem dabei +ist die Veränderlichkeit des Vectors, denn dadurch könnte +man über den Alias-Zeiger vn +Werte einzufügen, die nicht typkonform sind. Aus diesem Grunde +würde der Compiler bereits die zweite Zeile der obigen Methode +mit einem Typfehler ablehnen. + + + + +
+Diese neue Typinkompatibilität hat nun einige Konsequenzen, die +sich vor allem dort bemerkbar machen, wo wir bisher intuitiv angenommen +haben, dass Ober- und Unterklasse zuweisungskompatibel sind. Ein Beispiel +ist etwa die Parametrisierung von Methoden, bei der man üblicherweise +die formalen Parameter etwas allgemeiner fasst, um die Methode vielseitiger +einsetzen zu können. + +
+Betrachten wir eine Methode zur Ausgabe aller Elemente unserer Zahlenliste. +Mit etwas Weitblick würde man sie so formulieren: + + +
+
+
+
+001 public static void printAllNumbers1(List<Number> numbers)
+002 {
+003 for (Number s : numbers) {
+004 System.out.println(s);
+005 }
+006 }
+
+ |
+
+Anstelle eines Vector<Double> +verallgemeinern wir auf List<Number>. +In der Annahme, dann nicht nur den Inhalt eines Vektors ausgeben zu +können, sondern auch den einer ArrayList +oder LinkedList +(die beide ebenfalls vom Typ List +sind), und zwar auch dann, wenn sie nicht Double-, +sondern auch Integer- +oder Long-Werte +enthalten (die ebenfalls vom Typ Number +sind). Diese Methode enthält nicht mehr Code als die speziellere +Form, ist aber viel universeller einzusetzen. Ergo würde sich +ein erfahrener Programmierer normalerweise dafür entscheiden, +sie auf diese Weise zu parametrisieren. + +
+Leider hat die Sache einen Haken. Zwar akzeptiert printAllNumbers1 +beliebige Collections vom Typ List, +aber eben nur, wenn sie Werte vom Typ Number +enthalten. Solche mit Double-, +Integer- +oder Long-Werten +lehnt sie - aus den oben beschriebenen Gründen - ab. Der praktische +Nutzen dieser Methode ist damit nur mehr gering. + +
+Um mehr Flexibilität zu gewinnen, wurde der Wildcard »?« +als Typparameter eingeführt. Wird das Fragezeichen anstelle eines +konkreten Elementtyps angegeben, bedeutet dies, das die Collection +beliebige Werte enthalten kann: + + +
+
+
+
+001 public static void printAllNumbers2(List<?> numbers)
+002 {
+003 for (Object o: numbers) {
+004 System.out.println(o);
+005 }
+006 }
+
+ |
+
+An diese Methode können nun Listen mit beliebig typisierten Elementen +übergeben werden. Allerdings gibt es beim Lesen der Elemente +keine Typsicherheit mehr. Am Kopf der for-Schleife +kann man erkennen, dass der Compiler die Listenelemente nun - wie +in früheren JDK-Versionen - lediglich als Werte des Typs Object +ansieht. Spezielle Eigenschaften sind damit unsichtbar bzw. müssen +mit Hilfe einer expliziten Typkonvertierung wieder sichtbar gemacht +werden. + + + + +
+Eine abgeschwächte Form des »?«-Wildcards sind die +gebundenen Wildcards (»bounded wildcards«). Sie entstehen, +wenn nach dem Fragezeichen das Schlüsselwort extends +angegeben wird, gefolgt vom Namen des Elementtyps. Dadurch wird ausgedrückt, +dass die Collection Elemente der angegebenen Klasse oder einer ihrer +Unterklassen enthalten kann: + + +
+
+
+
+001 public static void printAllNumbers3(List<? extends Number> numbers)
+002 {
+003 for (Number s : numbers) {
+004 System.out.println(s.doubleValue());
+005 }
+006 }
+
+ |
+
+Gebundene Wildcards realisieren am ehesten die bisher bekannten Regeln +von Typkonformität bei Ober- und Unterklassen von Elementen. +? extends O bedeutet, dass die +Collection Elemente des Typs O +oder einer (auch über mehrere Stufen) daraus abgeleiteten Unterklasse +enthalten kann. An einen formalen Parameter vom Typ List<? +extends Number> können also aktuelle Parameter +des Typs Vector<Double>, +ArrayList<Integer> usw. +übergeben werden. +
+
![]() |
+
+
+ +Zu beachten ist allerdings, dass die Wildcards nur das Lesen +der Elemente flexibilisieren. Das Einfügen neuer Elemente ist +dagegen nicht mehr erlaubt und wird vom Compiler unterbunden. +Genauer gesagt, verboten ist der Aufruf von Methoden, die mindestens +einen generisch typisierten Parameter haben. Die Gründe entsprechen +den oben erläuterten. Wäre es nämlich zulässig, +in eine List<? extends Number> +einen Double +einzufügen, so würde ein Problem entstehen, wenn es sich +tatsächlich beispielsweise um einen Vector<Integer> +handeln würde, denn dieser darf ja kein Element des Typs Double +aufnehmen. Daher sorgt der Compiler dafür, dass bei der Verwendung +von Wildcards und gebundenen Wildcards die Collection nur noch zum +Lesen der Elemente verwendet werden darf. Versuche, neue Elemente +einzufügen, werden mit einem Compilerfehler quittiert. |
+
+
|
+![]() |
+
+Die Implementierung von generischen Collections ist in Java im Prinzip +Sache des Compilers, die virtuelle Maschine merkt davon nichts. Der +Compiler interpretiert den Quelltext, prüft die Typ-Parameter +und erzeugt Bytecode mit den erforderlichen Typ-Konvertierungen, Warnungen +und Fehlermeldungen. Das Laufzeitsystem, die virtuelle Maschine, arbeitet +dabei im Grunde wie in früheren JDK-Versionen. Dabei bleibt insbesondere +die Integrität der VM stets erhalten und Typfehler führen +zu kontrollierten (ClassCast-) Exceptions, wie in früheren JDK-Versionen. +Trotz allen Aufwands lassen sich nämlich Fälle konstruieren, +bei denen fehlerhaft typisierte Werte in eine generische Collection +eingefügt werden. Wir werden dazu im nächsten Abschnitt +ein einfaches Beispiel sehen. + +
+Anders als Templates in C++ erzeugen generische Java-Klassen keinen +zusätzlichen Programmcode. Alle Instanzen einer generischen Klasse +verwenden denselben Bytecode, getClass +liefert ein und dasselbe Klassenobjekt und die statischen Variablen +werden gemeinsam verwendet. Es ist nicht erlaubt, in statischen Initialisierern +oder statischen Methoden auf den Typparameter einer Klasse zuzugreifen, +und die Anwendung des instanceof-Operators +auf eine typisierte Klasse ist illegal. + +
+Es ist zulässig, generische Collections und herkömmliche
+Collections gemeinsam zu verwenden. Erwartet beispielsweise ein Methodenparameter
+eine typisierte Collection, so kann auch eine untypisierte Collection
+übergeben werden, und umgekehrt. In diesem Fall kann der Compiler
+die Typsicherheit des Programmcodes allerdings nicht mehr sicherstellen
+und generiert vorsichtshalber eine »unchecked warning« :
+
+
+Note: Some input files use unchecked or unsafe operations.
+Note: Recompile with -Xlint:unchecked for details.
+
+
+
+
+Durch Rekompilieren mit -Xlint:unchecked +werden Detailinformationen ausgegeben. Die Entwickler des JDK gehen +davon aus, dass in Zukunft nur noch typisierte Collections verwendet +werden, und diese Warnungen nach einer gewissen Übergangszeit +der Vergangenheit angehören werden. + +
+Neben den hier beschriebenen Eigenschaften gibt es noch eine ganze +Reihe weiterer Aspekte von generischen Klassen, auf die wir hier nicht +näher eingehen wollen. Sie werden meist gebraucht, um spezielle +Sonderfälle bei der Entwicklung von Collection-Klassen zu realisieren; +für »Otto Normalprogrammierer« sind die meisten von +ihnen weniger relevant. Die nachfolgende Aufzählung listet einige +von ihnen auf, weitere Informationen können der Sprachspezifikation +bzw. der Dokumentation der J2SE 5.0 oder 6.0 entnommen werden: +
| Titel + | Inhalt + | Suchen + | Index + | DOC + | Handbuch der Java-Programmierung, 5. Auflage, Addison +Wesley, Version 5.0.1 + |
| << + | < + | > + | >> + | API + | © 1998, 2007 Guido Krüger & Thomas +Stark, http://www.javabuch.de + |