# Generische Liste



## SlaterB (27. Jul 2007)

kann ich folgenden Code generisch anders machen,  so dass ich nicht die Fehlermeldung bekomme?

```
public class Test2
{
    public static void main(String[] args)
        throws Exception
    {
        MyList myList = null;

        // Type mismatch: cannot convert from element type Object to A
        for (A a : myList.getTList())
        {
        }
    }

}

class A
{

}

class MyList<T extends A>
{
    private List<T> entries = new ArrayList<T>();

    public List<T> getTList()
    {
        return entries;
    }
}
```
ich habe paar Sub-Listen mit Elementen als Subklassen von A, 
will manchmal aber einfach nur die Liste mit A-Elementen allgemein verarbeiten 
und dabei nicht ständig MyList<T> schreiben müssen oder ähnlich geklammertes,


----------



## SlaterB (27. Jul 2007)

ich darf nicht mal eine zweite Operation erstellen, die entries auf List<A> castet,
irgendwie scheint jegliches Generics ausgeschaltet?


```
public class Test2
{
    public static void main(String[] args)
        throws Exception
    {
        MyList myList = null;

        // for (A a : myList.getTList())
        // {
        // }


        // Type safety: The expression of type List needs unchecked conversion to conform
        // to List<Long>
        List<Long> l = myList.getLongList();
    }

}


class A
{

}


class MyList<T extends A>
{
    private List<T> entries = new ArrayList<T>();

    public List<T> getTList()
    {
        return entries;
    }

    public List<Long> getLongList()
    {
        return new ArrayList<Long>();
    }
}
```


----------



## Bjoern2 (27. Jul 2007)

Wenn deine "myList" null ist, kannst du logischerweiße auch nicht drauf zugreifen! ;-)

Edit: Du solltest auch vielleicht besser mit den runden Klammern casten.
Also 
	
	
	
	





```
ClassA a = (ClassA)myClassB;
```


----------



## SlaterB (27. Jul 2007)

das ist ein Testprogramm, es geht mir um die Warning beim Zugriff, 
die ist unabhängig von der Bestimmung des Objektes, also habe ich diesen unwichtigen Teil weggelassen..
(sind ja eh nur Testklassen)


----------



## Bjoern2 (27. Jul 2007)

(Siehe mein Edit oben drüber, wegen "casten".)


----------



## SlaterB (27. Jul 2007)

was möchtest du mir damit sagen?
das Ziel des ganzen ist ja gerade, nicht casten zu müssen?


----------



## Guest (27. Jul 2007)

Versuch's mal damit:


```
public class Test2
{
	public static <T extends A> void main(String[] args) throws Exception
	{
		MyList<T> myList = null;

		for (A a : myList.getTList())
		{
		}
	}
}
```

Die NullPointerException gibt's beim Starten natürlich immer noch 

Fred


----------



## SlaterB (27. Jul 2007)

interessant, aber leider bei mir nicht sinnvoll,
wie gesagt: ohne irgendwelches Geklammere bei der Benutzung
(Benutzung in zig verschiedenen Operationen/ Klassen)

nur zusätzliche/ andere Generics in der Listen-Klasse, falls das noch irgendwie hilft


----------



## Bjoern2 (27. Jul 2007)

Hast du mal sowas ausprobiert?

```
List l = (List)myList.getLongList();
```


----------



## SlaterB (27. Jul 2007)

was willst du mir denn damit sagen?
List<Long> l = myList.getLongList(); 
soll funktionieren und nicht durch was anderes ersetzt werden


----------



## Bjoern2 (27. Jul 2007)

So klappts wunderbar:


```
import java.util.*;

class MyList<T extends A>
{
    private List<T> entries = new ArrayList<T>();

    public List<T> getTList()
    {
        return entries;
    }

    public List<Long> getLongList()
    {
        return new ArrayList<Long>();
    }
}
```


```
import java.util.*;

public class Test2
{
    public static void main(String[] args)
        throws Exception
    {
        MyList myList = new MyList<A>();
        List l = myList.getLongList();
    }

}
```


```
class A
{

}
```


Die erwähnte Fehlermeldung war übrigens kein Fehler, sondern eine Warnung.
Hätte sich also trotzdem kompilieren lassen.


----------



## SlaterB (27. Jul 2007)

deine Aussage ist also, dass ich 
a.) alle Generics rausnehmen kann
oder
b.) die Meldungen ignorieren kann,

beides ist absolut klar und von Anfang an nicht das Thema,
es geht ja darum, Generics zu verwenden.. 
(ok, so richtig deutlich bin ich auch nicht in der Beschreibung)

und um es nicht aus den Augen zu verlieren: das Ziel ist das erste Beispiel, da ist es ne Fehlermeldung, keine Warning,


----------



## JPKI (27. Jul 2007)

Muss die Klasse MyList nicht Collection erweitern, damit du mittels foreach-Schleife drauf zugreifen kannst?


----------



## SlaterB (27. Jul 2007)

ich greife mit for-each auf myList.getTList() zu, welche eine Liste zurückgibt


----------



## Bjoern2 (27. Jul 2007)

Hast du es mal mit einer ganz einfachen Zählschleife versucht?


```
for(i=0;i<myList.size();i++)
{
    //Mach was. mit myList.get(i);
}
```

Oder so:

```
Iterator it = myList.iterator();
while(it.hasNext())
{
    Object obj = it.next();
}
```


----------



## SlaterB (27. Jul 2007)

du bist ja hartnäckig 

for -Schleife und Iterator wären zum einen noch schlimmer als nur mal eben<T> zu schreiben, was ich vermeiden will,
zum anderen würde das nicht verhindern, dass ich immer noch nur den Typ Object und nicht den Typ A bekomme,

for (Object obj : myList.getTList()) 
      { 
      } 

funktioniert ja bereits, das ist nicht das Problem,
ich will aber A (und nein, ich will nicht casten  )


----------



## Bjoern2 (27. Jul 2007)

Warum machst du eigentlich nicht sowas:

```
public class Test2
{
    public static void main(String[] args) throws Exception
    {
        MyList myList = new MyList();

        for(int i=0;i<myList.size();i++)
        {
            A a = myList.get(i); 
            //Er müsste jetzt eigentlich wissen, dass das geht, weil MyList von A erbt 
            //und der Funktion gesagt wurde, dass die Liste aus MyList besteht.
        }

    }

}

class A
{

}

class MyList extends A
{
    private List<MyList> entries = new ArrayList<MyList>();

    public List<MyList> getTList()
    {
        return entries;
    }
}
```
(Achtung! Nicht ausprobiert.)

Also das T ist jetzt weg.
Ist das für dich jetzt in Ordnung? ;-)


Übrigens versteh ich nicht, warum du meinst, dass eine FOR-Schleife schlechter wäre, als eine FOREACH-Schleife. ???:L


----------



## SlaterB (27. Jul 2007)

ist das jetzt noch erst gemeint?

aus einer generischen MyList, die generische Elemente A enthält,
machst du eine nichtgerische MyList, die von A erbt und nichtgenerische  Elemente MyList enthält? 
hat das noch was mit meinem Programm zu tun?

> warum du meinst, dass eine FOR-Schleife schlechter wäre, als eine FOREACH-Schleife. 

schlechter weil Code länger, das ist ja einer der Gründe, warum es for-each überhaupt gibt:
schicke kurze Syntax


----------



## Roar (27. Jul 2007)

sorry björn aber dein code ist totaler blödsinn. er funktioniert nicht, er macht auch keinen sinn und hat mit der frage auch nichts mehr zu tun :bloed: 
slater: damit keine warnungen mehr kommen musst du deine myList parametisieren (dort kommt doch auch eine warnung..)


----------



## Bjoern2 (27. Jul 2007)

Roar hat gesagt.:
			
		

> sorry björn aber dein code ist totaler blödsinn. er funktioniert nicht, er macht auch keinen sinn und hat mit der frage auch nichts mehr zu tun :bloed:


Ja. Sorry. Hab meinen Fehler gerade eingesehen.
War ein Denkfehler von mir. Sorry.


----------



## Bjoern2 (27. Jul 2007)

Roar hat gesagt.:
			
		

> slater: damit keine warnungen mehr kommen musst du deine myList parametisieren (dort kommt doch auch eine warnung..)



Also so? 

```
public class Test2
{
    public static void main(String[] args) throws Exception
    {
        MyList<DERTYP> myList = null;

        for (A a : myList.getTList())
        {

        }
    }

}
```


----------



## SlaterB (27. Jul 2007)

> damit keine warnungen mehr kommen musst du deine myList parametisieren (dort kommt doch auch eine warnung..)

naja, 
"Usage of a raw type" ist bei mir abgeschaltet, 
sonst hätte ich ja bei jedem allgemeinen Zugriff auf die Superklasse oder jeder Hilfsoperation wie


```
public static boolean isEmpty(Collection collection)
    {
        return collection == null || collection.isEmpty();
    }
```
Warnung oder Schreibaufwand,

oder Map, Class und Comparable, die ich überall als einfache Basisklassen verwende.. 

und wie gesagt: selbst wenn es nur eine Warning wäre,
aber das ist im ersten Beispiel ja direkt ein Fehler

wenn's nicht geht, dann nicht, kein Problem


----------



## Roar (27. Jul 2007)

SlaterB hat gesagt.:
			
		

> oder Map, Class und Comparable, die ich überall als einfache Basisklassen verwende..


gerade bei solchen klassen sind die generics doch besonders sinnvoll



> aber das ist im ersten Beispiel ja direkt ein Fehler


auch im ersten beispiel musst du myList parametisieren


----------



## SlaterB (27. Jul 2007)

ja klar, ich meinte nur, dass ich mit einer Warning leben könnte wenn ich nicht parametrisiere,
also dass das Auftreten dieser Raw-Type-Warning für mich kein endgültiger Grund wäre, den Parameter reinzunehmen,

aber diese Fehlermeldung da macht mir aber Probleme, deswegen werde ich parametrisieren müssen (oder andere Hilfspoerationen verwenden)

--------

> gerade bei solchen klassen sind die generics doch besonders sinnvoll 

jeder wie er möchte,
ich z.b. mache mehrere Datenbankanfragen,
"aggegriere Tabelle x nach Feld y"
y kann String oder Integer, BigDecimal oder Enum sein,
die Paare (y, Gruppensumme) kommen dann in Maps, in Listen,
werden sortiert, formatiert usw.
Comparable als Basisklasse ist da super, habe dann im Quellcode 100x Comparable irgendwo als Parameter oder Exemplarvariable stehen,
das überall zu parametrisieren wäre ein reiner Unfall


----------



## Guest (27. Jul 2007)

SlaterB hat gesagt.:
			
		

> Comparable als Basisklasse ist da super, habe dann im Quellcode 100x Comparable irgendwo als Parameter oder Exemplarvariable stehen,
> das überall zu parametrisieren wäre ein reiner Unfall


Mir ist immer noch nicht ganz klar, was überhaupt der Sinn von MyList ist. Soll das nur eine Abkürzung sein, um nicht immer List<T> schreiben zu müssen oder wie? Dann mach's doch so:


```
public class Test2
{
	public static void main(String[] args) throws Exception
	{
		MyList myList = null;

		for (A a : myList)
		{
		}
	}
}

class A
{
}

class MyList extends ArrayList<A>
{
	private static final long serialVersionUID = -4961928283264201181L;
}
```

Wahrscheinlich habe ich aber einfach nicht kapiert, wozu MyList überhaupt gut sein soll.

Fred


----------



## Guest (27. Jul 2007)

Anonymous hat gesagt.:
			
		

> ```
> class MyList extends ArrayList<A>
> {
> private static final long serialVersionUID = -4961928283264201181L;
> ...


Schöner ist es natürlich mit Interfaces:


```
interface MyList extends List<A>
{
}
```

Fred


----------



## Marco13 (27. Jul 2007)

Um die Warnung wegzukriegen gibt es IMHO und AFAIK zwei Möglichkeiten. Entweder man schreibt eben nicht

```
MyList myList = null;
```
sondern

```
MyList<A> myList = null;
```
Auch wenn ich nicht sehe, was daran so schlimm sein soll, wolltest du das ja nicht - falls ich dich richtig verstanden habe. 

Die andere Möglichkeit wäre sowas wie

```
class MyList extends MyListImpl<A>
{}

class MyListImpl<T extends A>
{
    private List<T> entries = new ArrayList<T>();

    public List<T> getTList()
    {
        return entries;
    }
}
```
aber so ein "Krampf", nur um sich das <A> zu ersparen (und dafür an den Stellen, wo man den Typ DOCH angeben will, immer MyList*Imp*<Typ> schreiben zu müssen) lohnt sich wohl nicht. 

Die Seiten zu
http://forum.java.sun.com/thread.jspa?threadID=456239&messageID=4082065
und
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6444048
hast du vermutlich schon gesehen. Und genau DAS wäre ja das, was du wolltest (falls ich dich richtig verstanden habe)


----------



## SlaterB (27. Jul 2007)

diese ganzen Vorschläge finde ich recht seltsam, die ändern ja total mein Programm, nehmen immer Generics raus..

MyList extends ArrayList ist nicht ganz falsch, ändert aber an der Genericsproblematik sicherlich nix, denn
class MyList extends ArrayList<A> 
müsste ja
class MyList<T extends A> extends ArrayList<T> 
oder so heißen, soll ja generisch sein

und zur Frage, warum nicht direkt so: MyList hat nunmal in Wirklichkeit noch zig andere Funktionen,
enthält neben der Liste auch noch eine Map der enthaltenen Objekte usw,
das ist ja letztlich egal


das Problem von 
class MyList extends MyListImpl<A> 
ist ebenso, dass MyList dann nicht mehr generisch wäre..

ich habe im Programm ja Objekte von Unterklassen
MyListB extends MyList*
MyListC extends MyList<C>

(B und C Unterklassen von A)

--------

MyList<A> 
sieht hier vielleicht nicht schlimm aus,
in Wirklichkeit steht dann aber überall
HistoryBaseList<SimpleHistoryElement>
statt einfach nur HistoryBaseList

und das finde ich blöde, überall im Programm <SimpleHistoryElement> zu wiederholen,
obwohl HistoryBaseList<T extends SimpleHistoryElement>
doch so definiert ist, dass SimpleHistoryElement drin ist,

das müsste man doch automatisch erkennen,

wenn ich von einer belieben dieser Liste die Elemente hole,
warum sind die vom Typ Object und nicht vom angegebenen Mindesttyp?

zurück zum MyList-Beispiel: es können nur A-Objeke oder Subklassen drin sein,
das sollte doch einfach erkennbar sein, ohne diese Info durch <A> redundant an zig Stellen im Programm zu wiederholen

die beiden Links scheinen damit nix zu tun zu haben, aber danke*


----------



## Roar (27. Jul 2007)

warum willst du MyList dann überhaupt generisch machen oder gibt es dann irgendwann eine HistoryBaseList<ComplexHistoryElement> für ein problem das sich nicht mit einer vernünftigen klassenhierarchie lösen lässt? ???:L


----------



## Marco13 (27. Jul 2007)

Die Links haben insofern damit zu tun, als dass du bei einer Deklaration wie

```
MyList myList = null;
```
dem Typ-Parameter "T" von MyList<T extends A> ja implizit "A" zuweisen willst. In Anlehung an die Links bräuchtest du eben ein Konstrukt wie

```
class MyList<T=A extends A> {...} // A ist damit der "Default-Wert" für T
```

Ich finde, dass deine Frage zwar gerechtfertigt ist, da ja schließlich eindeutig und unmißverständlich (zur Compilezeit!) erkannt werden könnte, dass die Liste IMMER Objekte vom Type 'A' enthalten muss. Aber damit würde vermutlich die Rückwärtskompatibilität kaputtgemacht oder so. Wenn man keinen Typ angibt, ist es eben "Object", und das extendet auch nichts... Find' dich damit ab :wink:


----------



## SlaterB (27. Jul 2007)

ich finde mich damit ab, ich frag ja nur 

@Roar:
ich habe mehrere History-Objekte in der Hierarchie und mehrere Listenklassen, 
eine für jeden Typ mit Funktionalität,

die Listenklassen erben nicht voneinander und haben auch feste Namen ohne <irgendwas>,
nur wenn ich gemeinsame Funktionalität für die Basisliste implementiere, die sich dann logischerweise auch nur auf die Basiselemente bezieht, muss ich ja mit der Basisklasse und <igitt> arbeiten,

ich finde Generics toll für solche Klassenhierarchien, 
aber man sollte sie verstecken können, und nicht bei jeder Benutzung daran erinnert werden,
manchmal stören sie einfach


----------

