# Aus einer Liste<Oberklasse> alle Elemente die eine bestimmte Unterklasse von Oberklasse haben filter



## student@work (1. Feb 2011)

Hallo.

Hinweis: Übungsaufgabe.
Wir haben die Voraussetzung (Einschränkung): Nur List, ArrayList und java.lang.*; verwenden zu können/dürfen.


Ich habe eine Liste, die Elemente des Typs Oberklasse enthält. Die Klasse Oberklasse ist abstract, 
von daher sind letztendlich nur Elemente vom Typ Unterklasse (extends Oberklasse) in der Liste enthalten.

Um alle Elemente aus der Liste zu erhalten, die ein Objekt vom Typ Unterklasse repräsentieren
könnte ich für jede Unterklasse jeweils eine eigene Methode der Form


```
/**
   * @return Eine Liste, die nur Objekte vom Typ Unterklasse enthält.
   */
List<Unterklasse> getUnterklasseList() {/* ... */}
```

schreiben.

Das Projekt könnte* jedoch mit der Zeit um weitere Unterklassen erweitert werden.
Daher müsste man dann bei jeder weiteren Unterklasse eine Methode der
Form getUnterklasseList() hinzufügen. Ich würde die Änderungen aber lieber lokal halten.

Meine Frage lautet: 

Gibt es einen allgemeineren Ansatz, evtl. mit Generics, Utility-Methode, ...? 
Wie wird das in der Praxis gehandhabt?

Dazu hatte ich eine Idee, die jedoch nicht ohne Ausgabe einer Warnung auskam.
Aufgrund von "Type Erasure" habe ich nun aber einige Probleme bekommen ...

Übersehe ich gerade etwas (Bin gerade am Durchstöbern der API ab ArrayList. Design Fehler, ...)? 
Gibt es eine einfache(re) Lösung für dieses Problem, ohne für
jede Unterklasse eine Filtermethode schreiben zu müssen?

Ich werde weiter darüber nachdenken, 
aber wenn mir hier jemand einen Tipp
geben kann, wäre dies sehr schön.


Viele Grüße, 

Marvin

---------------------------------------------------------------------------------------------------
Zu * muss ich sagen: Dies passiert wenn überhaupt nur sehr selten, von daher wäre der Ansatz mit
den einzelnen Methoden für die Aufgabe sogar in Ordnung. Dennoch würde mir eine allgemeinere
Lösung besser gefallen.


----------



## student@work (1. Feb 2011)

Noch ein Hinweis: Mit Reflection würde es sicher gehen, 
aber die sind nach der genannten Voraussetzung nicht erlaubt.

Wenn es keinen eleganten workaround gibt, werde ich wohl bei * bleiben.

Was meint Ihr?


Grüße,

Marvin


----------



## Landei (1. Feb 2011)

Der Standardweg wäre sowas:

```
List<Oberklasse> ober = ...
List<Unterlasse> unter = new Arraylist<Unterklasse>();
for(Oberklasse o : ober) {
   if(o instanceof Unterklasse) {
      unter.add((Unterklasse) o); //dieser Cast ist durch den vorherigen Test "sicher"
   }
}
```

Das Schlüsselwort [c]instanceof[/c] würde ich nicht als "Reflection" ansehen, und ein Cast ist in irgend einer Form ist notwendig (wenn die Unterklassen-Liste korrekt getypt ist und man nicht auf Rawtype-Tricks ausweicht). Falls dich die Warnung stört, kannst du auch [c]unter.add(Unterklasse.class.cast(o));[/c] schreiben, was aber auch nicht "besser" ist, weil genau wie vorher eine [c]ClassCastException[/c] fliegt, wenn der Typ nicht passt.


----------



## bygones (1. Feb 2011)

wäre das eine alternative ?

```
private static List<Foo> getSubclasses(Class<? extends Foo> theClass, List<Foo> superClasses) {
        List<Foo> subList = new ArrayList<Foo>();
        for (Foo foo : superClasses) {
            if (foo.getClass().equals(theClass)) {
                subList.add(foo);
            }
        }
        return subList;
}
```
bzw dann als nicht statisch in deiner applikation etc etc


----------



## Landei (1. Feb 2011)

Die beiden Versionen sind unterschiedlich. Meine Version würde auch Objekte von Unter-Unterklassen erlauben, während bei dir nur exakt Unterklassen-Objekte berücksichtigt werden, aber keine davon abgeleiteten Klassen. Und natürlich ist es nicht sehr hypsch, die Objekte nach der Unterklasse zu "filtern", aber danach dennoch eine Liste der Oberklasse zurückzugeben.


----------



## student@work (1. Feb 2011)

Hallo, vielen Dank für Eure Hilfe.


(=:


```
/**
	 * ...
	 * 
	 * @param superclassList Liste mit Objekten der Superklasse (T).
	 * @param subclassType Subtyp vom generischen Typ der Liste (also von T),
	 *                     Objekte dieses Typs werden gefiltert.
         * @return Liste, die nur Objekte von dem Typ enthält, welcher als subclassType Parameter angegeben wurde.
	 */
	public static <T> List<T> getSubclasses(Class<? extends T> subclassType, List<T> superclassList) {
		
		List<T> subclassList= new ArrayList<T>();
		for (T t : superclassList) {
			if (t.getClass().equals(subclassType)) {
				subclassList.add(t);
			}
		}
		return subclassList;
	}
```

Der Ansatz von bygones gfällt mir.
Soetwas (=: habe ich mir auch gewünscht, wenn da nur
dieser klitzekleine Schönheitsfehler mit dem Rückgabetyp nicht wäre.

Bekommen wir das noch irgendwie in den Griff?

Den Ansatz von Landei probiere ich gerade noch in Form einer
Methode wie oben zu implementieren. Ich sehe da aber ein Problem:
Mit dem Begriff Unterklasse meinte ich eine konkrete Unterklasse.
Also irgendeine von den Unterklassen, die es gerade gibt.
Beim instanceof-Operator muss ich diese konkrete Unterklasse 
angeben. Ich möchte da aber auch flexibel bleiben.
Aber wenn das irgendwie funktioniert wäre es toll.

Fällt Euch ein Weg ein, wie man das machen könnte?


Grüße,

Marvin


----------



## student@work (1. Feb 2011)

(editiert: T2 extends T1)

Noch ein abendlicher Nachtrag:

Aktuell sieht mein Code so aus:


```
// T2: Subklasse
	// T1: Superklasse
	public static <T1, T2 extends T1> List<T2> getSubclasses(Class<? extends T1> subclassType, List<T1> superclassList) {
		
		List<T2> subclassList = new ArrayList<T2>();
		for (T1 t1 : superclassList) {
			if (t1.getClass().equals(subclassType)) {
				subclassList.add((T2) t1);
			}
		}
		return subclassList;
	}
```

Wenn ich bei den Generics nichts falsch gemacht habe, erfüllt dies soweit meine Anforderungen.
Dass die Methode nur direkte Unterklassen/"Kind-Unterklassen" zurückgibt ist soweit ok.

Leider gibt es eben noch eine Warnung, die ich auch nicht unter den Teppich kehren möchte.
Was könnte ich zur Sicherheit dagegen tun: dokumentieren oder ist die Implementierung 
sicher genug, dass ein kurzer Kommentar genügt?

Seht Ihr noch Probleme?
Was meint Ihr?


Grüße,

Marvin


PS: Hab mich im Forum angemeldet, kann aber scheinbar noch nicht editieren (...?). Deswegen der Doppelpost.


----------



## Landei (1. Feb 2011)

Die Warnung solltest du so loswerden:

```
public static <T1, T2 extends T1> List<T2> getSubclasses(Class<T2> subclassType, List<T1> superclassList) {
        List<T2> subclassList = new ArrayList<T2>();
        for (T1 t1 : superclassList) {
            if (t1.getClass().equals(subclassType)) {
                subclassList.add(subclassType.cast(t1));
            }
        }
        return subclassList;
    }
```


----------



## student@work (1. Feb 2011)

Ok, vielen Dank.

Wenn nicht noch jemand einen Fehler findet oder ein Risiko 
mitteilen möchte, dann ist das Thema erledigt.

Gute Nacht.


----------

