Erklähre den Unterschied zwischen super und extends.
| Antwort/ answer | |
|---|---|
Welche dieser Code-Zeilen compiliert einwandfrei?:
List a = new ArrayList();
List<?> b = new ArrayList<String>();
List<String> c = new ArrayList();
List<String> d = new ArrayList<String>();
List<String> e = new ArrayList<?>();
List f = new ArrayList<String>();
| Antwort/ answer | |
|---|---|
Konsequenterweise können nicht nur eigene generische Klassen, sondern auch eigene generische Methoden angelegt werden:
public <T> void getPersNr(T t) {
List list = new ArrayList ();
}
Hierbei ist zu beachten, dass die Typvariable (hier: <T>) vor dem Rückgabetyp angegeben werden mus.
Eine Einschränkung (z.B. mit <T extends Angestellter>) ist im selben Maße möglich wie bei eigenen generischen Klassen
Es kann auch die Wildcard ? mit T ersetzt werden, hier ein letztes Beispiel einer Klassendefinition (zumindest fürs erste
):
class generic_Types <T extends Angestellter>{ .. }
Genau wie bei der Wildcard können in diesem Zusammenhang nur Objekte vom Typ Angestellter oder dessen abgeleiteter Klassen aufgenommen werden.
generic_Types <Angestellter> a_generic= new generic_Types <Angestellter> ();
generic_Types <Buchhalter> b_generic = new generic_Types <Buchhalter> ();
können daher problemlos angelegt werden,
generic_Types <Integer> c_generic = new generic_Types <Integer>();
gibt einen CompilerFehler, da falscher Objekt-Typ
Da generische Klassen gerne im SCJP abgefragt werden, kommen die nächsten Tage noch weitere Beispiele, in diesem Falle eine generische Klasse mit Übergabe von mehreren Werten:
class generic_Types <T, X>{
T t; //Variablenname für Element
X x; //Variablenname für Element
generic_Types(T t, X x){
this.t=t;
this.x=x;
}
}
Hier ist das Besondere die Übergabe von beliebigen Elementen, die dann in den internen Variablen gespeichert und weiterverarbeitet werden können.Hier noch der Vollständigkeit halber noch die Anlage einer Instanz:
generic_Types a_generic= new generic_Types(1, “abc”);
Wie man eine eigene generische Klasse anlegt, wissen wir jetzt, aber wie sieht es mit dem Hinzufügen beliebiger Elemente aus?
Hierfür muss unsere Beispiel-Klasse um eine Funktion erweitern werden:
public void add_ToList (T element){list.add(element);}
Das Hinzufügen ist dann recht einfach:
a_generic.add_ToList(new Angestellter());
a_generic.add_ToList(new Buchhalter());
a_generic.add_ToList(new Verkäufer());
a_generic.add_ToList(new Date());
Wie bereits beschrieben, macht es keinen Unterschied, welcher Objekt-Typ hinzugefügt wird.
Was Stellvertreter sind, wissen wir nun. Heute geht es um deren Anwendung mit dem Ziel, eine eigene generische Klasse anzulegen.
Gehen wir z.B. davon aus, dass auf allen Listen die gleichen Methoden angewandt werden sollen; in unserem Beispiel wollen wir vielleicht die jeweiligen Listen in einer privaten Variable wegspeichern und mit den gleichen Methoden weiterbearbeiten.
Wir gehen also von folgenden List aus:
List <Angestellter> a= new ArrayList<Angestellter>();
List <Buchhalter> b = new ArrayList <Buchhalter>();
List <Verkäufer> c = new ArrayList <Verkäufer>();
List <Date> d = new ArrayList <Date>();
Ohne eine eigene generische Klasse müsste für jeden Objekt-Typ eine eigene Funktion angelegt werden, in der die List gespeichert wird. Zusätzliche Funktionen für die jeweiligen Objekt-Typen müssten auch mehrfach implementiert werden, so dass der Aufwand ziemlich groß ist.
Deswegen wird eine generische Klasse angelegt:
class generic_Types <T>{
private List <T> list;
generic_Types(List <T> list){
this.list=list;
}
public List get_List (){
return list;
}
}
Hierein können dann ganz komfortabel die verschiedenen Lists gespeichert und bearbeitet werden:
generic_Types a_generic= new generic_Types(a);
generic_Types b_generic= new generic_Types(b);
generic_Types c_generic= new generic_Types(c);
generic_Types d_generic= new generic_Types(d);
Statt der Wildcard, gibt es auch die Möglichkeit, sogenannte Stellvertreter zu definieren;
<E> ist der Platzhalter für alle Arten von Collections
<T> ist der Platzhalter für alle Arten von Nicht-Collections
Daher wird <E> eher bei Methoden, bzw. Übergaben von Collections und <T> eher bei der Defintion/Anlage von Collections benutzt.
Hierbei ist wichtig zu wissen, das dies nur Vorgaben sind; es kann jeder andere Großbuchstabe anstelle von E/T benutzt werden.
alles was an eine andere Methode übergeben werden kann; kann auch direkt zugewiesen werden:
Deswegen hier nur die genannten Beispiele in der Zusammenfassung:
List <Angestellter> a = new ArrayList <Angestellter>();
List <Angestestellter> b= new ArrayList <Buchhalter>();
List <? extends Angestellter> c = new ArrayList <Angestellter>();
List <? super Buchhalter> d = new ArrayList <Angestellter>();
List <?> e = new ArrayList <Angestellter>();
List <Object> f = new ArrayList <Angestellter>(); // Type mismatach
List <Object> g = new ArrayList <Object>();
List <? extends Angestellter> h = new ArrayList <Buchhalter>();
List <? extends Angestellter> i = new ArrayList <? super Buchhalter>(); // Type mismatch
List <? super Angestellter>j= new ArrayList <Buchhalter>(); // Type mismatch
Es gelten zusätzlich die gleichen Regeln für das Hinzufügen von Objekten.
Heute wollen wir uns mal die Übergabe von List ohne jegliche Einschränkungen anschauen:
public static void checkStatus_list (List <?> a){ … }
oder
public static void checkStatus_list (List<Object> a){ … }
Auf den ersten Blick sieht es aus, als wären beide Methoden gleich, aber es gibt Unterschiede:
Bei der Übernahme von <?> ist die Funktion add(Object) ausgeschaltet; ein CompilerFehler wird ausgeben. Hintergrund ist einfach, dass Probleme bei verschiedenen Objekttypen, bzw. deren späterer Weiterbehandlung vermieden werden soll.
Bei der Übernahme von (List<Object> a) kann auch nur der Typ List <Object> übergeben werden, und keine Subklassen. Somit ist für unser Beispiel (List mit Objekten vom Typ Buchhalter, Verkäufer und Angestellter) diese Methode nicht brauchbar.