www.wikidata.de-de.nina.az
Generische Programmierung in Java wird durch sog Generics seit Java 1 5 ermoglicht Der Begriff steht synonym fur parametrisierte Typen Die Idee dahinter ist zusatzliche Variablen fur Typen einzufuhren Diese Typ Variablen reprasentieren 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 meistens gewahrleistet werden Jedoch nicht immer 1 Inhaltsverzeichnis 1 Das Konzept 2 Praktische Beispiele 3 Varianzfalle 3 1 Invarianz 3 2 Kovarianz 3 3 Kontravarianz 3 4 Uneingeschrankte parametrische Polymorphie 4 Weblinks 5 EinzelnachweiseDas Konzept BearbeitenAb Version 5 0 Tiger 2004 veroffentlicht steht auch in der Programmiersprache Java mit den Generics ein syntaktisches Mittel fur die generische Programmierung zur Verfugung Damit lassen sich Klassen und Methoden Methoden auch unabhangig von ihren Klassen mit Typen parametrisieren Damit werden der Sprache einige ahnliche Moglichkeiten eroffnet die sich vergleichbar bei den Templates in C bieten Prinzipiell gibt es aber durchaus wesentliche Unterschiede Wahrend in Java uber die Schnittstelle der Typparameter parametrisiert wird wird in C direkt uber den Typ des Typparameters selbst parametrisiert Der Quelltext eines C Templates muss fur den Anwender d h beim Einsetzen des Typparameters verfugbar sein wahrend ein generischer Java Typ auch als ubersetzter Bytecode veroffentlicht werden kann Fur verschiedene konkret verwendete Typparameter produziert der Compiler duplizierten Zielcode Beispielsweise bietet die Funktion std sort in C die Moglichkeit alle Container zu sortieren die bestimmte Methoden anbieten hier speziell begin und end die jeweils einen Iterator liefern und deren Typparameter den operator lt implementiert oder explizit eine andere Vergleichsfunktion angegeben wurde Ein Nachteil der sich durch dieses System ergibt ist die fur den Programmierer schwierigere Ubersetzung Der Compiler hat keine andere Moglichkeit als den Typparameter in jedem Fall durch den geforderten konkreten Typ zu ersetzen und den ganzen Code erneut zu kompilieren Sehr leicht konnen bei unpassenden Typparametern und anderen Problemen komplizierte und unverstandliche Compiler Meldungen entstehen was einfach mit der Tatsache zusammenhangt dass die konkreten Anforderungen an die Typparameter unbekannt sind Die Arbeit mit C Templates erfordert deshalb eine luckenlose Dokumentation der Anforderungen an einen Typparameter Durch Template Metaprogrammierung konnen die meisten Anforderungen Basisklasse Vorhandensein von Methoden Kopierbarkeit Zuweisbarkeit etc auch in speziellen Konstrukten abgefragt werden wodurch sich lesbarere Fehlermeldungen ergeben Obgleich sie standardkonform sind werden diese Konstrukte jedoch nicht von allen Compilern unterstutzt Dagegen sind den generischen Klassen und Methoden in Java die Anforderungen engl constraints an ihre eigenen Typparameter bekannt Um eine Collection ohne Comparator zu sortieren mussen die enthaltenen Elemente vom Typ Comparable sein also dieses Interface implementiert haben Der Compiler muss lediglich prufen ob der Typparameter ein Untertyp von Comparable ist und kann damit schon sicherstellen dass der Code korrekt ist d h die erforderliche Methode compareTo verfugbar ist Weiterhin wird ein und derselbe Code fur alle konkreten Typen verwendet und nicht jedes Mal dupliziert Praktische Beispiele BearbeitenEin Programm verwendet eine ArrayList um eine Liste von JButtons zu speichern Bisher war die ArrayList auf den Typ Object fixiert List list new ArrayList list add new JButton Button 1 list add new JButton Button 2 list add new JButton Button 3 list add new JButton Button 4 list add new JButton Button 5 for int i 0 i lt list size i JButton button JButton list get i button setBackground Color white Man beachte die notwendige explizite Typumwandlung auch Cast genannt sowie die Typunsicherheit die damit verbunden ist Man konnte versehentlich ein Objekt in der ArrayList speichern das keine Instanz der Klasse JButton ist Die Information uber den genauen Typ geht beim Einfugen in die Liste verloren der Compiler kann also nicht verhindern dass zur Laufzeit bei der expliziten Typumwandlung von JButton eine ClassCastException auftritt Mit generischen Typen ist in Java Folgendes moglich List lt JButton gt list new ArrayList lt JButton gt list add new JButton Button 1 list add new JButton Button 2 list add new JButton Button 3 list add new JButton Button 4 list add new JButton Button 5 for int i 0 i lt list size i list get i setBackground Color white Beim Auslesen ist nun keine explizite Typumwandlung mehr notwendig beim Speichern ist es nur noch moglich JButtons in der ArrayList list abzulegen Ab Java7 ist die Instanzierung generischer Typen vereinfacht worden Die erste Zeile in obigem Beispiel kann seit Java 7 folgendermassen geschrieben werden List lt JButton gt list new ArrayList lt gt Durch Kombination von generischen Typen mit den erweiterten For Schleifen lasst sich obiges Beispiel kurzer fassen List lt JButton gt list new ArrayList lt gt list add new JButton Button 1 list add new JButton Button 2 list add new JButton Button 3 list add new JButton Button 4 list add new JButton Button 5 for JButton b list b setBackground Color white Ein Beispiel fur eine generische Klasse die zwei Objekte von beliebigem aber einander gleichem Typ beinhaltet liefert der folgende Beispielcode public class DoubleObject lt T gt private T object1 private T object2 public DoubleObject T object1 T object2 this object1 object1 this object2 object2 public String toString return this object1 this object2 public static void main String args DoubleObject lt String gt s new DoubleObject lt gt abc def DoubleObject lt Integer gt i new DoubleObject lt gt 123 456 System out println DoubleObject lt String gt s s toString System out println DoubleObject lt Integer gt i i toString Varianzfalle BearbeitenIn Java konnen die nachfolgenden Varianzfalle unterschieden werden Sie bieten jeweils eine vollig eigenstandige Flexibilitat beim Umgang mit generischen Typen und sind jeweils absolut statisch typsicher Invarianz Bearbeiten Bei Invarianz ist der Typparameter eindeutig Damit bietet Invarianz die grosstmogliche Freiheit bei der Benutzung des Typparameters Beispielsweise sind fur die Elemente einer ArrayList lt Integer gt alle Aktionen erlaubt die auch bei der direkten Benutzung eines einzelnen Integers erlaubt sind inklusive Autoboxing Beispiel List lt Integer gt list new ArrayList lt Integer gt Integer x list get index list get index methodeVonInteger list set index 98347 Autoboxing entspricht Integer valueOf 98347 int y list get index Auto Unboxing Diese Moglichkeiten werden mit wenig Flexibilitat bei der Zuweisung von Objekten der generischen Klasse selbst erkauft Beispielsweise ist Folgendes nicht erlaubt List lt Number gt list new ArrayList lt Integer gt und das obwohl Integer von Number abgeleitet ist Der Grund liegt darin dass der Compiler hier nicht mehr sicherstellen kann dass keine Typfehler auftreten Mit Arrays die eine solche Zuweisung erlauben hat man schlechte Erfahrungen gemacht OK Integer ist abgeleitet von Number Number array new Integer 10 ArrayStoreException zur Laufzeit Double gt Integer sind nicht zuweisungskompatibel array 0 new Double 5 0 Kovarianz Bearbeiten Man bezeichnet Arrays als kovariant was besagt Aus T extends V folgt T extends V oder allgemeiner Aus T extends V folgt GenerischerTyp lt T gt extends GenerischerTyp lt V gt Es verhalt sich also der Array Typ bzgl der Vererbungshierarchie genauso wie der Typparameter Kovarianz ist auch mit generischen Typen moglich allerdings nur mit Einschrankungen so dass Typfehler zur Kompilierzeit ausgeschlossen werden konnen Referenzen mussen mit der Syntax extends T explizit als kovariant gekennzeichnet werden T heisst upper typebound also der allgemeinste Typparameter der erlaubt ist List lt extends Number gt list list new ArrayList lt Double gt list new ArrayList lt Long gt list new ArrayList lt Integer gt Typfehler vom Compiler list set index myInteger OK aber Warnung vom Compiler unchecked cast List lt Integer gt list set index myInteger Das Ablegen von Elementen in diesen Listen ist nicht moglich da dies wie oben beschrieben nicht typsicher ist Ausnahme null kann abgelegt werden Bereits zur Kompilierzeit tritt ein Fehler auf Allgemeiner gesagt ist die Zuweisung extends T nicht erlaubt Moglich dagegen ist das Auslesen von Elementen Number n list get index OK Integer i list get index Typfehler Es muss sich bei extends Number nicht um ein Integer handeln Integer j Integer list get index OK Die Zuweisung extends T T oder Basisklasse ist also erlaubt nicht aber die Zuweisung extends T abgeleitet von T Generics bieten also wie Arrays kovariantes Verhalten verbieten aber alle Operationen die typunsicher sind Kontravarianz Bearbeiten Kontravarianz bezeichnet das Verhalten der Vererbungshierarchie des generischen Typs entgegen der Hierarchie seines Typparameters Ubertragen auf das obige Beispiel wurde das bedeuten Eine Liste lt Number gt ware zuweisungskompatibel zu einer Liste lt Double gt Dies wird folgendermassen bewerkstelligt List lt super Double gt list list new ArrayList lt Number gt list new ArrayList lt Double gt list new ArrayList lt Object gt Ein Objekt das sich kontravariant verhalt darf keine Annahmen daruber machen inwiefern ein Element vom Typ V von T abgeleitet ist wobei T der lower Typebound ist im Beispiel von super Double ist T Double Deshalb kann aus den obigen Listen nicht gelesen werden Fehler list konnte vom Typ List lt Object gt sein Number x list get index Fehler list konnte List lt Object gt oder List lt Number gt sein Double x list get index Die einzige Ausnahme Objects sind auf jeden Fall in der Liste Object x list get index Nicht erlaubt da nicht typsicher ist also die Zuweisung super T abgeleitet von Object Unschwer zu erraten Im Gegenzug kann in eine solche Liste ein Element abgelegt werden List lt super Number gt list list add new Double 3 0 OK list hat immer den Typ List lt Number gt oder List lt Basisklasse von Number gt Damit ist die Zuweisung Double gt T immer erlaubt Uneingeschrankte parametrische Polymorphie Bearbeiten Zu guter Letzt bieten Generics noch ganzlich polymorphes Verhalten an Hierbei kann keinerlei Aussage uber die Typparameter gemacht werden denn es wird in beide Richtungen keine Grenze angegeben Dafur wurde die Wildcard definiert Sie wird durch ein Fragezeichen reprasentiert List lt gt list list new ArrayList lt Integer gt list new ArrayList lt Object gt list new ArrayList lt String gt Der Typparameter selbst kann hierbei nicht genutzt werden da keine Aussage moglich ist Lediglich die Zuweisung T Object ist erlaubt da T auf jeden Fall ein Object ist Im Gegenzug ist garantiert dass der Code mit allen Ts arbeiten kann Nutzlich kann so etwas sein wenn man nur mit dem generischen Typ arbeitet Keine Informationen uber den Typparameter notig kann beliebige Listen aufnehmen int readSize List lt gt list return list size Zur Verdeutlichung dass hier Wildcards unnotig sind und es eigentlich gar nicht um irgendeine Varianz geht sei folgende Implementierung der obigen Funktion angegeben lt T gt int readSize List lt T gt list return list size Weblinks BearbeitenIna Brenner Tutorial zu Generics in Java von der Autorin eines Buchs zur Java Zertifizierung SCJP deutsch Klaus Kreft Angelika Langer Artikelserie zu Generics in Java im JavaSpektrum deutsch Kapitel zu Generischen Datentypen aus dem Galileo Openbook Java ist auch eine Insel deutsch Einzelnachweise Bearbeiten Java and Scala s Type Systems are Unsound Abgerufen im 1 Januar 1 Abgerufen von https de wikipedia org w index php title Generische Programmierung in Java amp oldid 219268355