Allgemeine Objekte vergleichen

Hallo zusammen,
Ich will mein Problem anhand eines Beispiels erläutern:

Ich habe 3 Arraylists mit verschiedensten Objekten. Die erste enthält Bücher, die zweite Autos und die dritte enthält die Kontakte aus meinem Adressbuch.
Ich will über 3 Knöpfe die zugehörige ArrayList in einer JList sortiert angezeigt haben. Alle 3 Klassen sind vergleichbar untereinander.

Ich habe bereits eine JList mit eigenem Model erstellt, die Objekte einer Klasse aufnehmen und sortieren kann.


...

public void sort(){
		Collections.sort(content);
		fireContentsChanged(this, 0, content.size());
	}

Das Problem ist nun, dass ich in dieser Liste nur Bücher abspeichern kann. Wenn ich also Autos angezeigt haben möchte, brauche ich eine andere Liste die angezeigt wird, da die Superklasse Object keine Vergleiche erlaubt.

Gibt es eine Möglichkeit, alle 3 Listen in der JList anzeigen zu können (nicht gleichzeitig, immer nur eine mit Objekten der gleichen Klasse), ohne auf ein eigenes Model zu verzichten und ohne 3 JLists zu erstellen?

Ich hoffe ihr könnt damit was anfangen :slight_smile:

Du könntest doch deine Klassen von einer Oberklasse/Interface zum Beispiel Showable erben lassen und dann in deiner JList die Showable Objekte haben.

interface Showable{
   String getDisplayText();
}

class Auto implements Showable{
   private int ps;
   private String marke;
   String getDisplayText(){
      return marke+" "+ps;
   }
}

Wie kannst du die Klassen miteinander vergleichen? Implementieren sie Comparable? Hast du einen Comparator? Haben sie eine gemeinsame Oberklasse?

Jede Klasse implementiert Comparable, die compareTo-Methode ist für jede Klasse entsprechend überschrieben.

Wenn alle Klassen Comparable implementieren, hast du damit doch dein Interface schon gefunden. Statt List einfach List<Comparable<?>> (oder ggf List<? extends Comparable<?>>).

Erstmal danke für die Hilfe, mit Interfaces kenne ich mich noch nicht so gut aus. Aber es funktioniert trotzdem noch nicht so wie ich will.

Wenn ich zur Initialisierung im Konstruktor

public Konstruktor (ArrayList<Comparable> eineListe){
...
}

stehen habe, dann motzt er an der Stelle

private eineMethode(){
   new Konstruktor(new ArrayList<Auto>());
}

rum, weil er ArrayList möchte. An einer Stelle erzeuge ich ja die spezifische ArrayList mit den Autos, und dort will ich nicht auf ArrayList gehen, weil mir das viele umständliche Casts beschert.

Wie gesagt, probier “? extends Comparable”. Ansonsten KSKB statt 3 Zeilen Code reinklatschen.

→ als Parameter der Methode/ des Konstruktors

Collections.sort() als Beispiel macht es noch paar Schritte aufwendiger:
public static <T extends Comparable<? super T>> void sort(List<T> list)

Danke für eure Tipps, ich glaube ich habe jetzt einigermaßen verstanden wie Interfaces funktionieren. :slight_smile:

Der Tipp von @Natac hat mich viele ArrayLists in meinem Code erstellen lassen. Da habe ich gemerkt, dass viele Methoden viel zu spezifisch sind (um beim Beispiel zu bleiben: Ich verwende z.Z. nur die Klasse Buch, die anderen Klassen kommen erst später nach).
Da ich einige Dinge allgemeiner schreiben muss lohnt es sich sogar, eine Superklasse für die alternativen Klassen in den ArrayLists zu schreiben. Das sollte mein Problem beheben und der Compiler akzeptiert alles :slight_smile:

@bERt0r : das „extends“ funktioniert nur, falls ich ein eigenes Interface erstelle (was du vermutlich weißt). Da alle Comparable verwenden brauche ich sowas ja aber nicht. Allerdings sagt der Compiler, dass ich ArrayList nicht dort einsetzen darf, wo ArrayList gefordert ist.

Und wie vergleichst du da Autos mit Büchern? Kann doch so nicht gehen - oder ist schlechtes Design (da würde ja in der Auto-Klasse Code sein, der was von Büchern weiß)

Ich würde da eher einen Comparator

implements Comparator<GemeinsameOberklasseOderInterface>

verwenden.

Okay da habe ich mich wohl missverständlich ausgedrückt:

Es wird nur gleiches mit gleichem verglichen. Die Klasse Bücher hat eine andere compareTo-methode als Autos. Und in der JList soll immer nur die Liste mit EINER Klasse (also entweder nur Bücher oder nur Autos etc.) angezeigt werden. Im Endeffekt geht es darum, eine (modifizierte) JList zu besitzen. Der Nutzer kann dann entscheiden, welche der ArrayLists (Bücher, Autos,…) er in dieser JList angezeigt haben möchte.

Ich hoffe es ist jetzt etwas klarer worauf ich hinaus möchte.

Ach so - aber dann geht es doch nicht um JList - sondern um ListModel?

Mach halt drei ListModels, implementiere da sort() und fertig.

Oder ein ListModel, das vom Typ

MeinModell<T extends Comparable> 

Bzw: das ist gar nicht so trivial, weil ja Events kommen können beim Ändern, dann neu sortiert werden muss etc.

http://www.oracle.com/technetwork/articles/javase/sorted-jlist-136883.html

Drei ListModels wäre halt CopyPaste und immer den Klassennamen in ArrayList<?> geändert. Da dachte ich das geht doch sicher auch einfacher. Abgesehen davon muss ich ja dann abfragen starten welches ListModel ich wähle.

Ich bin gerade an der Superklasse dran, ich melde mich nochmal sobald sich da was tut.

[QUOTE=TheAceOfSpades]Drei ListModels wäre halt CopyPaste und immer den Klassennamen in ArrayList<?> geändert. Da dachte ich das geht doch sicher auch einfacher. Abgesehen davon muss ich ja dann abfragen starten welches ListModel ich wähle.

Ich bin gerade an der Superklasse dran, ich melde mich nochmal sobald sich da was tut.[/QUOTE]

Deswegen hatte ich das ja um 8:20 Uhr vorgeschlagen, eine Überklasse oder ein Interface zu erstellen, von dem die 3 Klassen erben :wink:

Naja, etwas einfacher könntest du es haben, wenn du nicht so „stark“ auf Generics setzt:

     private List<T> liste = new ArrayList<T>();
}```

und erstellen würdest du das Model dann halt so: `new MyListModel<Auto>();`. Wenn du aber wirklich unterschiedliche Lists in deinem Model unterstützen möchtest, dann musst du erstmal die Feinheiten von Generics verstehen. Also so Sachen wie `<? extends ...>` oder `<? super ...>`. Ich hab grad etwas bedenken obs hilfreich ist oder nicht, aber vllt kannst du ja mal versuchen das hier Nachzuvollziehen:

```import java.util.ArrayList;
import java.util.List;

interface Alpha {}
interface Beta extends Alpha {}

public class Gamma implements Beta {

    public void beispiel(List<Beta> liste) {
       liste.add(this);     // geht
    }

    public void beispielExtends(List<? extends Beta> liste) {
        liste.add(this);    // geht nicht (readonly)
    }

    public void beispielSuper(List<? super Beta> liste) {
        liste.add(this);    // geht
    }

    public void use() {
        List<Alpha> alpha = new ArrayList<Alpha>();
        List<Beta> beta = new ArrayList<Beta>();
        List<Gamma> gamma = new ArrayList<Gamma>();

        alpha.add(this);        // geht
        beta.add(this);         // geht
        gamma.add(this);        // geht

        beispiel(alpha);        // geht
        beispiel(beta);         // geht
        beispiel(gamma);        // geht nicht

        beispielExtends(alpha); // geht nicht
        beispielExtends(beta);  // geht
        beispielExtends(gamma); // geht

        beispielSuper(alpha);   // geht
        beispielSuper(beta);    // geht
        beispielSuper(gamma);   // geht nicht
    }
}```

Das mit den Interfaces ist glaube ich gerade noch ein bischen viel für mich, aber danke fürs aufzeigen. Ich versuche es mal im Hinterkopf zu behalten für das was kommt…mir spukt da schon was im Kopf rum wie ich es doch gebrauchen könnte.

Mein Problem habe ich aber ganz schlicht durch Erstellen einer Superklasse “Alternative” gelöst. In dem Kontext in dem ich das Ganze benötige hätte ich früher oder später sowieso darauf zugreifen müssen.

Die Lösung, falls das mit der Superklasse nicht funktioniert hätte, wäre, wie @Tomate_Salat es vorgeschlagen hat, das mit <? extends ...> gewesen. Leider muss ich mich darin noch etwas einlesen und zum Glück brauche ich es gerade nicht :P.