Advanced
Java
Services
|
Generics |
Das klassische Problem, das zur Einführung von generics geführt hat
ArrayList list = new ArrayList(); //1
list.add("Hello World"); //2
list.add(new Integer("1")); //3
String hi = (String)list.get(0); //4
String low = (String)list.get(1); //5 RuntimeException: ClassCastException
Der cast ist notwendig, da next() den Typ Objekt zurückliefert. Da in eine ArrayList beliebige
Objekte aufgenommen werden können, ist kein anderer Rückgabetyp möglich. Obiger Code wird vom
Compiler nicht beanstandet, führt aber zur Laufzeit zu einer ClassCastException. Wollte der
programmierer nur Strings in die ArrayList aufnehmen, so ist in Zeile 3 ein falsches Element
aufgenommen worden. Es gab bisher keine Möglichkeit, das den Compiler prüfen zu lassen. Ab 1.5
kann man nun aber beim Erstellen eines Containers angeben, welcher Elementtyp gespeichert werden
soll. Die neue Syntax ermöglicht eine Überprüfung zur Compile-zeit und ist somit wesentlich weniger
fehleranfällig als der nachträgliche cast, der damit überflüssig wird.
ArrayList<String> list = new ArrayList<String>(); //1
list.add("Hello World"); //2
list.add(new Integer("1")); //3 Error at compiletime: cannot find symbol :
// method add(java.lang.Integer)
String hi = list.get(0); //4 cast überflüssig
Durch die Typangabe in den spitzen Klammern wird eine ArrayList erzeugt, die ausschließlich Strings
aufnehmen kann, man nennt sie eine "ArrayList von Strings". Bei allen Methoden der Klasse, die Elemente
in die Liste aufnehmen wird vom Compiler
der Typ Object durch den Typ String ersetzt. Damit kann der Compiler in Zeile 3 mit der entsprechenden
Fehlermeldung reagieren. Die gefürchtete ClasscastException kann nicht mehr auftreten. Der Gewinn ist
größer als man zunächst glauben mag. Mit dem nachträglichen notwendige Cast kann dieses eine Statement
richtig sein (oder auch nicht...) Durch den Einsatz von ArrayList als generische Klasse wird eine
ArrayList von Strings vereinbart. Egal wo man Instanzen dieses generischen Typs im Programm verwendet
und wie oft, immer prüft der Compiler, ob die ArrayList als ArrayList von Strings verwendet wird.
War bisher die Signatur der add()-Methode
boolean add(Object ob)
so heißt es jetzt
boolean add(E ob)
wobei E für einen beliebigen Typ steht, der durch den in der aktuellen Vereinbarung erklärten Typ
steht.
ArrayList<Integer> intList = new ArrayList<Integer>();
Damit wird intList zu einer "sicheren" Liste. Eine Aufnahme von Objekten anderen Typs ist nicht
mehr möglich. Fehler diesbezüglich werden zur Compilezeit erkannt.
Am besten fasst man ArrayList<Type> als eine Art von Typ auf, das hilft für die Konsequenzen,
die sich aus der neuen Spracheigenschaft ergeben.
ArrayList<X> ist nicht typverwandt mit ArrayList<Y>
ArrayList<Object> listOfObjects = new ArrayList<Object>(); //1
ArrayList<String> listOfStrings = new ArrayList<String>(); //2
ArrayList<Number> listOfNumbers = new ArrayList<Number>(); //3
ArrayList<Integer> listOfIntegers = new ArrayList<Integer>(); //4
Das folgende kann man erwarten:
// kann alles aufnehmen
listOfObjects.add( new Object() );
listOfObjects.add( "hello" );
listOfObjects.add( new Integer("17") );
// kann nur Strings aufnehmen
listOfStrings.add( "world" );
// kann nur Integers aufnehmen
listOfIntegers.add( new Integer("17") );
// kann Numbers und alle Unterklassen von Numbers aufnehmen
Number num = new Float("16.99")
listOfNumbers.add( num );
listOfNumbers.add( new Integer("17") );
listOfNumbers.add( new Double("3.14") );