# Generics und Comparable



## Guest (16. Sep 2007)

hallo zusammen,
ich brauch ein Interface, das wie Comparable eine Methode compareTo enthält. Dies wird benötigt um Objekte von diesem Interface einfach über Collections.sort sortieren zu können.
Um einfach nur Objekte vergleichen zu können brauch ich kein extra-interface, da meine Klasse Comparable implementieren kann:


```
public class MyObject implements Comparable<MyObject> {
    public int compareTo(MyObject m) {

    }
}
```

Allerdings sollen meine Klassen auch eine weitere Methode implementieren, die z.B. ein Objekt zurückgeben können:


```
public class MyObject implements Comparable<MyObject> {
    public int compareTo(MyObject m) {

    }

    MyObject newObjectAfterOperation() {

    }
}
```

So gehts ja, aber ich dachte mir ich stelle ein Interface bereit, das von den Klassen implementiert wird:


```
public interface MyComparable<T extends MyComparable> extends Comparable<T> {
    int compareTo(final T obj);
    T newObjectAfterOperation();
}
```

So dass ich nachher schreiben kann:


```
public class MyObject implements MyComparable<MyObject> {
    public int compareTo(MyObject m) {

    }

    MyObject newObjectAfterOperation() {

    }
}
```

Wenn ich das wie angegeben mache meldet er keine Fehler. Wenn ich aber jetzt versuche eine Liste von Objekten anzulegen und versuche diese zu sortieren, meldet er boundmismatch.


```
List<MyComparable<MyObject>> test = 
            new ArrayList<MyComparable<MyObject>>();
...
Collections.sort(test);
```

Ich kenn mich mit Generics nicht so aus, wollte aber zeigen das ich zumindest was versucht habe...

In der Liste sollen nur Objekte der gleichen Klasse sein, die jeweils MyComparable implementiert. Allerdings weiss ich vorher nicht welche konkrete Klasse verwendet wird, deswegen kann ich nicht einfach direkt MyObject sortieren, sondern verwende das Interface MyComparable.

Hoff. ist das Problem klar geworden. Danke im Voraus.


----------



## SlaterB (17. Sep 2007)

also 
List<MyObject> test = new ArrayList<MyObject>();
geht,
List<MyComparable> test = new ArrayList<MyComparable>();
auch, 
was willst du mehr, was reicht an diesen nicht?

warum MyComparable<MyObject> nicht geht, kann ich allerdings nicht sagen


nächstes Mal bitte die Fehlermeldung komplett + idealerweise ein Testprogramm,
warum soll sich das jeder selber zusammenschreiben?
(außer die, die das blind überblicken  )


```
public class MyObject
    implements MyComparable<MyObject>
{
    public int compareTo(MyObject m)
    {
        return 0;
    }

    public MyObject newObjectAfterOperation()
    {
        return null;
    }

    public static void main(String[] args)
    {
        List<MyObject> test = new ArrayList<MyObject>();
        test.add(new MyObject2());
        Collections.sort(test);
        System.out.println(test);
    }
}

class MyObject2
    extends MyObject
{

}

interface MyComparable<T extends MyComparable>
    extends Comparable<T>
{
    int compareTo(final T obj);

    T newObjectAfterOperation();
}
```


----------



## Beni (17. Sep 2007)

Es würde gehen, wenn du dein Interface anders schreibst:

```
interface MyComparable<T extends MyComparable<T>> extends Comparable<MyComparable<T>> {
```
... aber wenn du das Interface implementierst, wirst du sehen, dass die compareTo-Methode nicht mehr so schön ist. Das "sort" verlangt offenbar die Parameter auf einem Weg, der dafür sorgt, dass in der Liste nur ein Element-Typ ist.

Btw: die Generics deines originalen MyComparable-Interfaces sind noch nicht vollständig, so wäre es besser:

```
public interface MyComparable<T extends MyComparable<T>> extends Comparable<T> {...}
```
Überall wo "MyComparable" auftritt, sollte man seinen Parameter ausfüllen.


----------



## Gast (17. Sep 2007)

Ok, danke für eure Antworten.
SlaterB: Tut mir leid, das nächste Mal werde ich das noch hinzufügen.

Warum es nicht reicht? Ich will in der Liste nur jeweils objekte einer bestimmten Klasse, die MyComparable implementiert, allerdings weiss ich vorher nicht welche konkrete Klasse das ist, ich weiss nur das verschiedene Klassen das Interface implementieren. 

Beni: Danke, werds mir nachher angucken, wenn ich wieder zu hause bin.


----------



## bygones (17. Sep 2007)

irgendwann musst du konkret sagen, welche typen in deiner liste sind....

d.h. wenn du die Liste instanzierst, musst du irgendwann den konkreten Typen angeben, oder du packst das ganze in eine generische Klasse die die Liste haelt....


----------



## Gast (17. Sep 2007)

Also, so siehts momentan aus:


```
public interface MyComparable<T extends MyComparable<T>> extends Comparable<T> {
    int compareTo(final T obj); 

    T newObjectAfterOperation(); 
}
```



```
public class MyObject implements MyComparable<MyObject>{
    public int compareTo(MyObject m) {
        return 0;
    }
    
    public MyObject newObjectAfterOperation() {
        return null;
    }
}
```



```
public class MyObject2 implements MyComparable<MyObject2>{
    public int compareTo(MyObject2 m) {
        return 0;
    }
    
    public MyObject2 newObjectAfterOperation() {
        return null;
    }
}
```



```
public class TestClass {
    public static void testMethod(MyComparable myComp) {
        List<MyComparable> list = new ArrayList<MyComparable>();
        
        for (int i = 0;i < 5; i++) {
            list.add(myComp.newObjectAfterOperation());
        }
        
        Collections.sort(list);
    }
    
    public static void main(String[] args) {
        MyComparable<MyObject2> m = new MyObject2();
        testMethod(m);        
    }
}
```

Ist das so richtig? dbac hat schon recht, irgendwo muss ich ein konkretes objekt erzeugen, das ist bei mir in der main. die methode testmethod bekommt ein Objekt vom Typ MyComparable, weiss aber nicht genau welche konkrete Klasse dahinter steckt (muss die methode auch nicht wissen).

Implementierung ist jetzt dummy, aber wollte wissen ob das jetzt so mit generics passt oder obs einfach nur syntakisch korrekt ist, semantisch aber falsch.


----------



## Beni (17. Sep 2007)

Ich würde den generischen Parameter von MyComparable nicht einfach so unterschlagen. Vielleicht sowas?

```
class TestClass {
    public static <M extends MyComparable<M>> void testMethod(M myComp) {
        List<M> list = new ArrayList<M>();
       
        for (int i = 0;i < 5; i++) {
            list.add(myComp.newObjectAfterOperation());
        }
       
        Collections.sort(list);
    }
   
    public static void main(String[] args) {
        // hier gibt es eine Veränderung!
        MyObject2 m = new MyObject2();
        testMethod(m);       
    }
}
```

*[Edit]*
Noch eine andere Variante, die ein bisschen näher beim Original ist:

```
class TestClass {
    public static <M extends MyComparable<M>> void testMethod(MyComparable<M> myComp) {
        List<M> list = new ArrayList<M>();
       
        for (int i = 0;i < 5; i++) {
            list.add(myComp.newObjectAfterOperation());
        }
       
        Collections.sort(list);
    }
   
    public static void main(String[] args) {
        MyComparable<MyObject2> m = new MyObject2();
        testMethod(m);       
    }
}
```


----------



## Gast (17. Sep 2007)

Ok danke. Noch etwas. Nehmen wir an die Testklasse hat ein Attribut vom Typ MyComparable. Dann müsste ich die Klasse doch auch mit Generics verwenden oder? 
Also so etwas:


```
class TestClass<T extends MyComparable<T>> { 
private MyComparable<T> comparable;
```
Richtig? 

Dann kann ich diesen Typ T aber nicht bei der statischen Methode verwenden. Dann muss ich bei der statischen Methode nach wie vor :


```
public static <T extends MyComparable<T>>
```

schreiben oder?


----------



## Beni (17. Sep 2007)

Zu 1: Richtig. Allenfalls reicht es "private T comparable" zu schreiben.

Zu 2: Generics kann man auch mit statischen Methoden zusammen verwenden. Die werden dort genau gleich wie angegeben, wie wenn man sie für normale Methoden verwenden möchte (nämlich direkt vor dem Rückgabetyp).

Da du scheinbar von Generics überflutet wirst, meine Gegenmittel:
- versuch mehr konkrete Typen zu verwenden
- lass die Generics in "geschützten Bereichen", also in dem Code den man von aussen nicht sieht und auch nicht direkt aufrufen kann, einfach weg.


----------



## Gast (17. Sep 2007)

Ok, kann Generics bei statischen Methoden auch "ganz normal verwenden". Allerdings kann ich nicht den Typ T, den ich bei der Klasse angebe, nicht in der statischen Methode angeben. Also so:



```
class TestClass<T extends MyComparable<T>> { 
private MyComparable<T> comparable; 

public static MyComparable<T>....

...
}
```

Ich kann natürlich bei der statischen Methode wieder T einschränken : <T extends ...>, aber ich hätte ja gerne genau den Typ T der auch in dem Attribut verwendet wird.

Danke für eure Hilfe. Ich finde das Thema teils noch etwas verwirrend..


----------



## Gast (17. Sep 2007)

Kann ich in dem Fall bei dem Attribut nicht den Typen T weglassen bzw. bei der Klasse?
Das Attribut kann von keiner externen Klasse direkt erfragt werden, wird aber intern benötigt, da auf dem Attribut best. Methoden aufgerufen werden. 

Dann hätte ich:


```
class TestClass {
private MyComparable comparable;

public static <T extends MyComparable<T>> TestClass createTestClass(MyComparable<T>) {
...
}
}
```

Habs oben wahr. falsch ausgedrückt. Ich erzeug über eine statische (Factory) Methode Objekte der Klasse, da die Klasse lediglich einen privaten Konstruktor hat. 

Das Attribut wird zur Berechnung anderer Attribute benötigt und kann nicht über get etc. erfragt werden.


----------



## Gast (19. Sep 2007)

Um nochmal auf das Thema zurückzukommen. Wäre es den Fall ok den typparameter beim attribut und der klasse wegzulassen, weil ich ja weiss das was "richtiges" von der factory-methode zurückkommt.


----------

