# Generics und Vererbung.



## Guest (16. Mrz 2005)

Hallo,

kann mir bitte jemand erklären, warum der folgende Code nicht geht?

```
List<? extends Number> list = new ArrayList<? extends Number>();
list.add(1);
list.add(2.5d);
```
Soll eine Collection sein, die alle möglichen Typen von Zahlen akzeptiert 
bzw. alles, was von Number abgeleitet ist (Integer, Double ...)

Ein anderes Beispiel (Basismodel + eine Erweiterung)

```
class A {
  private int a;
    
  public A(int a) {
    setA(a);
  }

  public int getA() {
    return a;
  }

  public void setA(int a) {
    this.a = a;
  }    
}
  
class B extends A {
  private int b;
    
  public B(int a, int b) {
    super(a);
    setB(b);
  }
    
  public int getB() {
    return b;
  }
    
  public void setB(int b) {
    this.b = b;
  }
}

...
List<? extends A> list = new ArrayList<? extends A>();
list.add(new B(1,1));
list.add(new B(1,2));
```
Die Fehlermeldung lautet
_Exception in thread "main" java.lang.Error: Unresolved compilation problems: 
	Cannot instantiate the type ArrayList<? extends A>
	Bound mismatch: The method add(? extends A) of type List<? extends A> is not applicable for the arguments (B). The wildcard parameter ? extends A has no lower bound, and may actually be more restrictive than argument B_

Irgendeine Idee?


----------



## stev.glasow (16. Mrz 2005)

Schreib einfach  
List<Number> list = new ArrayList<Number>(); 
bzw.
List<A> list = new ArrayList<A>();


----------



## Beni (16. Mrz 2005)

Mit "List<? extends Number> list" sagst du, dass list jede Liste mit irgendwelchen Beschränkungen die auch Number sind, sein kann. Z.b. Vector<Double>, ArrayList<Integer>...
Das man aber einer ArrayList<Integer> keinen Double zuweisen kann, ist klar. Und weil das in deinem Code potentiell möglich ist, gibts ein Fehler.

"new ArrayList<? extends Number>();" ist schlicht und einfach ungültig. Das hat keine Aussagekraft, du musst eine echte Begrenzung angeben (keine ?).


----------



## Guest (16. Mrz 2005)

:shock: Hmm.. so geht es.
Kannst Du bitte ein Beispiel für das "? etends Whatever" zeigen?
Mir ist der Unterschied nicht ganz klar.

Danke.


----------



## Beni (16. Mrz 2005)

Eine Methode wie das hier:

```
public void doSomething( List<? extends Number> list){
  for( ...  // z.B. ein System.out.println für alle Nummern
}
```

Kann auch mit einem "Vector<Double>" aufgerufen werden.

Würde es nur "List<Number> list" heissen, wäre das nicht möglich. (Denn dann könnte man in dieser doSomething-Methode z.B. Integer in die Liste schieben, was für den Vector<Double> nicht gut wäre)


----------



## stev.glasow (16. Mrz 2005)

Beispiel :

```
public static void foo(List<Number> numbers)
{
  for (Number s : numbers) {
     System.out.println(s.doubleValue());
   }
}

public static void bar(List<? extends  Number> numbers)
{
  for (Number s : numbers) {
     System.out.println(s.doubleValue());
   }
}

...

List<Number> a = new LinkedList<Number>();
a.add(1);
a.add(1.1);

List<Integer> b = new LinkedList<Integer>();
b.add(1);
b.add(2);

foo(a);
foo(b); // nicht möglich da explizit ein Typ 'List<Number>' erwartet wird.
bar(a);
bar(b); // ist möglich, da Integer von Number erbt
```

Klor?
[edit] ah Beni war wesentlich schneller.


----------



## Guest (16. Mrz 2005)

Danke, jetzt hab ich es endlich geschnallt ;-) 

```
public void ausgabe(List<? extends Number> list) {
  ...
}

List<Integer> l1 = new ArrayList<Integer>();
...
List<Double> l2 = new ArrayList<Double>();
...
ausgabe(l1);
ausgabe(l2);
```
Das "extends" bezieht sich auf den Typen der Liste. In der Methode "ausgabe" 
werden alle List-Objekte akzeptiert, deren Element von Number abgeleitet sind.

Sachen gibt's :lol:


----------



## stev.glasow (16. Mrz 2005)

Wieso ist eigentlich nicht gleich alles automatisch "? extends  Blub"  ?


----------



## Guest (16. Mrz 2005)

stevg hat gesagt.:
			
		

> Wieso ist eigentlich nicht gleich alles automatisch "? extends  Blub"  ?


Damit man sich die Casts auf konkrete Typen sparen kann, nehme ich an.


----------



## stev.glasow (16. Mrz 2005)

Wie meinst das?
Casten muss ich doch hier auch nicht:

```
public static void bar(List<? extends  Number> numbers)
{
  for (Number s : numbers) {
     System.out.println(s.doubleValue());
   }
}
```


----------



## Guest (16. Mrz 2005)

Mal auf die Gefahr hin, dass wie aneinander vorbei reden. :wink: 

Angenommen, man hat ein Framework, wie das Commons-Collections von Apache,
wo irgendwelche ausgefallene Methoden zur Manipualation von Zahlenreihen vorhanden
sind. Das Framework arbeitet z.B. mit allen Typen zusammen, die von Number erben.
In Deinem Programm verwendest Du aber nur Integer, möchtest trotzdem das Framework
verwenden. Die Methoden des Frameworks haben dann eine Signatur wie 
	
	
	
	





```
public static void doSomeCrazyStuff(List <? extends Number> list);
```
Du verwendest es aber mit 
	
	
	
	





```
List<Integer> list = new ArrayList<Integer>();
```
ein anderer wieder mit 
	
	
	
	





```
List<Double> list = new ArrayList<Double>();
```
Ich denke, dass dies der Unterschied ist.
Bei
	
	
	
	





```
public static void doSomeCrazyStuff(List <Number> list);
```
müsstest Du List<Number> übergeben und u.U. zig Casts in Deinem Code verwenden.

Korrigiert mich bitte, wenn etwas falsch ist. Ich denke aber, ich hab' es endlich kapiert. :wink:


----------



## stev.glasow (17. Mrz 2005)

Ich würde gern wissen warum die Einschränkung ohne extends besteht.

Außerdem verstehe ich immer noch nicht was du mit dem Casten sagen willst. Um in der Methode doSomeCrazyStuff, egal welche Variante, die Elemente als int vorliegen zu habem muss ich die Casten: 
int x = (int)dieListe.get(1122); // <<< hier musst du bei beiden Varianten casten, egal ob 'dieListe' mit oder ohne extends übergeben wurde (mal davon abgesehen, dass das sehr unschön ist). Oder meintest du was anderes?


----------



## Guest (17. Mrz 2005)

Ich meine das, was Du in Deinem Beispiel mit den zwei Methoden 'foo' und 'bar' gezeigt hast.
Bei der Variante mit  'List<? extends Number>' als Parameter kannst Du jede Liste übergeben, 
deren Elemente von Number erben. Ohne '<? extends Number>', also mit 'List<Number>' als 
Parameter, bist Du gezwungen 'List<Number>' an die Methode zu übergeben und musst außerhalb 
der Methode wie wild casten, wenn Du verschiedene Typen verwenden möchtest.
Oder anders ausgedrückt, eine Methode mit der Signatur

```
public void a(List<Number> list);
```
akzeptiert nur 'List<Number>' als Parameter.
Eine Methode mit der Signatur
	
	
	
	





```
public void a(List<? extends Number> list);
```
akzeptiert die Typen List<Integer|Double|Long usw.>


----------



## stev.glasow (17. Mrz 2005)

Achso außerhalb. Da hast du recht,  List<Integer> in List<Number> umzuformen wäre mies. Das erklärt aber nicht warum ohne extends eine Beschränkung besteht, darfür muss es doch einen Sinn geben.  :bahnhof:


----------



## Guest (17. Mrz 2005)

Ich denke, dass der Unterschied einfach daran liegt, dass man ohne 'extends' einen 
bestimmten Typen von List erzwingt. 
So gesehen macht List<? extends Number> wenig Sinn, müsste schon konkreter sein 
(Integer etc.).

Ein zweiter, nicht unbedeutender, Unterschied ist dann der Inhalt. Bei List<Number> 
kannst Du in der Methode eine gemischte Liste erwarten (verschiedene Typen von Daten drin),
bei List<? extends Number> werden zwar verschiedene List-Typen akzeptiert aber deren 
Elemente sind alle garantiert vom gleichen Typ (bzw. Basistyp).

Die Verwirrung entsteht, denke ich, durch das Schlüsselwort 'extends'.
Es bezieht sich nicht auf die Java-Syntax im Sinne von 'Integer extends Number' sondern 
'ParameterTypB extends ParameterTypA'. Oder so ähnlich :wink: 
Denk da an einen Preprocessor, der vor dem eigenlichen Compilieren zuerst den Code
von Preprocessor-Anweisungen und Templates 'bereinigt' und den zu compilierenden 
Code generiert.

Ich glaube, wenn ich noch weiter darüber nachdenke, wird ein Buch draus "Me against the generics" :lol:


----------



## stev.glasow (17. Mrz 2005)

> Bei List<Number>
> kannst Du in der Methode eine gemischte Liste erwarten (verschiedene Typen von Daten drin),
> bei List<? extends Number> werden zwar verschiedene List-Typen akzeptiert aber deren
> Elemente sind alle garantiert vom gleichen Typ (bzw. Basistyp).


  :bahnhof: 
Bei List<? extends Number> kann ich auch eine Liste vom Typ List<Number> übergeben

Wieso erklärst du mir das eigentlich ständig? Ich will wissen *warum* es diese Einschränkung gibt wenn kein extends angegeben wurde.

Entweder verstehen wir uns miss oder (min) einer von uns beiden sieht nicht durch.  :roll:


----------



## Guest (17. Mrz 2005)

stevg hat gesagt.:
			
		

> Bei List<? extends Number> kann ich auch eine Liste vom Typ List<Number> übergeben


Als eine von vielen Möglichkeiten. Bei List<Number> hast Du *nur* die eine.


			
				stevg hat gesagt.:
			
		

> Wieso erklärst du mir das eigentlich ständig? Ich will wissen *warum* es diese Einschränkung gibt wenn kein extends angegeben wurde.


Bleib cool, ich versuche nur zu antworten. Jeder denkt in etwas anderen Bahnen, so dass es schwierig ist, den Gedankengänge eines anderen zu folgen.


			
				stevg hat gesagt.:
			
		

> Entweder verstehen wir uns miss oder (min) einer von uns beiden sieht nicht durch.  :roll:


Beides. Wir sind mental inkompatibel. :wink:


----------



## stev.glasow (17. Mrz 2005)

OK, ich bleib cool.



			
				Anonymous hat gesagt.:
			
		

> stevg hat gesagt.:
> 
> 
> 
> ...


Das wusste ich bereits, denn ich und Beni haben dir das ja so erklärt. Und die Tatsache dass man auch eine Liste vom Typ List<Number> übergeben kann und diese Ausage 


> Bei List<Number>
> kannst Du in der Methode eine gemischte Liste erwarten (verschiedene Typen von Daten drin),
> bei List<? extends Number> werden zwar verschiedene List-Typen akzeptiert aber deren
> Elemente sind alle garantiert vom gleichen Typ (bzw. Basistyp).


 wieder sprechen sich meiner Meinung nach.


----------



## Guest (17. Mrz 2005)

stevg hat gesagt.:
			
		

> > Bei List<Number>
> > kannst Du in der Methode eine gemischte Liste erwarten (verschiedene Typen von Daten drin),
> > bei List<? extends Number> werden zwar verschiedene List-Typen akzeptiert aber deren
> > Elemente sind alle garantiert vom gleichen Typ (bzw. Basistyp).
> ...


Ehm.. wo Du es schreibst. Sollte umgekehrt sein und zwar wegen:
	
	
	
	





```
public void a(List <Number>list) {
  list.add(Integer.valueOf(1)); // OK. Alle Elemente sind garantiert von Number abgeleitet.
  ...
}

public void a(List <? extends Number>list) {
  list.add(Integer.valueOf(1)); // funktioniert nicht, da list auch List<Double> o.a. sein kann
  ...
}
```

???:L


----------



## stev.glasow (17. Mrz 2005)

Stimmt, war mein Fehler.
 Beni hat mir das grad klar gemacht.


			
				Chat hat gesagt.:
			
		

> 13:44:11 Beni: muss mal gucken
> 13:45:08 stevg: wenn nicht ist's auch ok
> 13:45:40 Beni: ach so, um beim List<Number>-Bsp zu bleiben: wenn du da z.B. eine List<Double> rein schieben könntest, könntest du dieser List<Double> eine beliebige Number, z.B. ein Integer, einfügen, und so was falsches produzieren
> 13:46:38 stevg: stimmt
> ...


----------



## Guest (17. Mrz 2005)

Was wäre das Forum ohne Beni? :wink:

Ich denke, wir haben jetzt schon alle Besonderheiten der Syntax 
durch. Oder fällt Dir noch etwas ein, was hier fehlt?


----------



## Ebenius (1. Sep 2005)

Also der Grund ist ganz einfach. 

Folgendes Beispiel: Ich möchte eine Methode haben, die in eine Collection eine Nummer einfügt, es sei denn, die Nummer ist durch 4 teilbar.
Hier funktioniert <? extends T> nicht.

```
void insertNumber(List<Number> l, Number n) {
   if(n.intValue() % 4 != 0)
     l.add(n); // geht, die Liste kann Numbers beinhalten und bekommt Number
 }

 /* NOPE */
 void insertNumberExtends(List<? extends Number> l, Number n) {
   if(n.intValue() % 4 != 0)
     l.add(n); // geht nicht, weil die Liste ArrayList<Double> sein könnte,
               // n vielleicht vom Typ Integer und die beiden passen einfach
               // nicht zusammen!
 }

 void insertNumberSuper(List<? super Number> l, Number n) {
   if(n.intValue() % 4 != 0)
     l.add(n); // geht, die Liste kann Objects, Numbers beinhalten und n ist
               // kompatibel
 }
```

Hier funktioniert jetzt <? extends T> nicht.

```
Number getFirstNumber(List<Number> list) {
   return list.get(0); // geht, list enthält Numbers
 }

 Number getFirstNumberExtends(List<? extends Number> list) {
   return list.get(0); // geht, list enthält Doubles, Integers, ...
 }

 /* NOPE */
 Number getFirstNumberSuper(List<? super Number> list) {
   return list.get(0); // geht nicht, da in dieser Liste auch Object-Instanzen
                       // sein können (die nicht mit dem R374ckgabewert der
                       // Methode kompatibel sind)
 }
```

Klar, soweit?

Cheers!


----------

