PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [JAVA] Casten von Vector<Float> nach Vector<Comparable> geht nicht?


Nasenbaer
2009-07-11, 16:44:51
Hi,
ich habe gerade versucht einen Vector<Float> nach Vector<Comparable> zu casten aber Java will das nicht. Dabei implementiert Float natürlich Comparable.

Meine Vermutung ist, dass das casten im Zusammenhang mit Generics eingeschränkt ist. Stimmt das und was kann man machen um die Limitierung zu umgehen?

Der_Donnervogel
2009-07-11, 17:14:46
Man kann über den Umweg Object gehen:

Vector<Float> a = new Vector<Float>();
Vector<Comparable> b = (Vector<Comparable>)(Object)a;


Allerdings ist die Typisierung mit Comparable sowieso etwas fragwürdig (Eclipse gibt da eh eine Warnung aus) denn man müsste das selbst wieder typisieren, da es als Comparable<T> definiert ist. Es dient also allenfalls der Lesbarkeit. Außerdem wenn es schon um Generizität geht würde ich auf Vector verzichten und stattdessen das List Interface (also java.util.List) verwenden und mit der ArrayList statt mit Vector arbeiten. Allenfalls wenn man die Synchronizierung von Vector braucht könnte das was bringen, aber selbst da ist es vermutlich besser die List über Collections.synchronizedList zu synchronisieren.

Nasenbaer
2009-07-11, 17:32:12
Im Beispiel habe ich auch von Vector<Float> auf AbstractList<Comparable> casten wollen aber schon selbst rausbekommen, dass AbstractList nicht das Problem ist.

Was ich will ist eine generische Methode, die eine Liste vergleichbarer Elemente entgegennimmt und den Index des Minimums zurückgibt.

Die Signatur sah dabei so aus:

int getMinimum(AbstractList<Comparable> list) {
// ...
if (list.get(i).compareTo(list.get(minIndex)) < 0) {
// ...
}
// ..
}

In der geposteten Codezeile gabs dann den Fehler: Type safety: The method compareTo(Object) belongs to the raw type Comparable. References to generic type Comparable<T> should be parameterized

Die Warnung hatte ich dann unterdrückt und dann fiel mir das Problem mit dem casten auf. Irgendwelche Ideen wie man sowas geschickter macht? :biggrin:

Achso und Vector nehme ich meistens weil der wahlfreie Zugriff konstante Zeit benötigt.

instinct
2009-07-11, 18:10:03
class Minimizer<T extends Comparable<T>>
{
int getMinimum(List<T> list) {
// ...
if (list.get(i).compareTo(list.get(minIndex)) < 0) {
// ...
}
// ..
}


Anlegen der Klasse mit:

Minimizer<Float> min = new Minimizer<Float>();
List<Float> list = new ...
....
int min = min.getMinimum(list);

Nasenbaer
2009-07-11, 18:15:58
Danke aber geht das echt nur einwandfrei über ne extra Klasse?

Monger
2009-07-11, 18:37:33
Generics kennen keinen Polymorphismus.
Auch wenn es danach aussieht: eine Liste von Float ist nicht (zwingendermaßen) eine Untermenge von einer Liste von Comparables!

Da ich es selber nicht gescheit erklären kann, verweise ich einfach mal auf den offiziellen Java Artikel:

http://java.sun.com/docs/books/tutorial/java/generics/subtyping.html
(Das ganze Tutorial über Generics ist sowieso lesenswert)

Und nicht wundern wenn du es das erste mal nicht verstehst. Ich verstehs bis heute nicht wirklich! ;)

Der_Donnervogel
2009-07-11, 18:51:38
Was ich will ist eine generische Methode, die eine Liste vergleichbarer Elemente entgegennimmt und den Index des Minimums zurückgibt.Wenns nur darum geht das kleinste Objekt heraus zu suchen, kann man das übrigens auch mit Collections.min() machen.
Achso und Vector nehme ich meistens weil der wahlfreie Zugriff konstante Zeit benötigt.Ja das ist schon klar. Ein Vector und eine ArrayList sind mehr oder weniger das selbe. Der Unterschied liegt darin, dass die ArrayList nicht synchronisiert ist, und somit etwas schneller ist. Falls man also keine Synchronisation braucht, sollte man die ArrayList nehmen.

Nasenbaer
2009-07-11, 19:15:06
Ah danke schonmal für den Tipp mit min().
Das mit der Synchronisierung wusste icht nicht - habs gleich mal umgestellt. :)

Gibt es denn einen Unterschied zwischen Collections.synchronizedList(new ArrayList(...)); und Vector? Oder ist Vector nur ein Überbleibsel älterer Java-Versionen?

@Monger

Werds bei Gelegenheit mal lesen. Hatte schon öfter Ärger mit Generics - gerade mit den Wildcards. :D

Gnafoo
2009-07-12, 01:36:10
Das eigentliche Problem dabei ist folgendes:

Stell dir vor, du hast eine List<Float> und castest die, um eine List<Comparable> daraus zu machen. Das Objekt ist das selbe geblieben, aber im Gegensatz zu vorher kannst du über die Methoden von List<Comparable> ein Comparable zur Liste hinzufügen, welches kein Float ist. Da es sich aber eigentlich um eine List<Float> handelt ist das natürlich Quatsch. Schließlich könntest du über andere Referenzen noch auf die List<Float> direkt zugreifen und was soll die dir dann an Stelle des Comparable, welches kein Float ist zurückliefern?

Ist aber im Prinzip dasselbe, was schon unter Mongers Link steht.

Edit und OT: wer das interessant findet, kann sich einmal C# ansehen. Ab C# 4.0 wird das dort nämlich in irgendeiner Form unterstützt, erfordert aber afaik eine Anpassung des Interfaces. Ich habe es mir noch nicht genauer angesehen, aber hier steht mehr unter "New Features in C# 4.0": http://code.msdn.microsoft.com/csharpfuture/Release/ProjectReleases.aspx?ReleaseId=1686

Nasenbaer
2009-07-12, 01:48:15
Stell dir vor, du hast eine List<Float> und castest die, um eine List<Comparable> daraus zu machen. Das Objekt ist das selbe geblieben, aber im Gegensatz zu vorher kannst du über die Methoden von List<Comparable> ein Comparable zur Liste hinzufügen, welches kein Float ist. Da es sich aber eigentlich um eine List<Float> handelt ist das natürlich Quatsch. Schließlich könntest du über andere Referenzen noch auf die List<Float> direkt zugreifen und was soll die dir dann an Stelle des Comparable, welches kein Float ist zurückliefern?
Ahh klar das stimmt natürlich. Die sind gar nicht so, die sich das ausgedacht haben. ;D
Dank min() hab ich aber erstmal nicht das Problem. *g*

Monger
2009-07-12, 09:37:43
Edit und OT: wer das interessant findet, kann sich einmal C# ansehen. Ab C# 4.0 wird das dort nämlich in irgendeiner Form unterstützt, erfordert aber afaik eine Anpassung des Interfaces. Ich habe es mir noch nicht genauer angesehen, aber hier steht mehr unter "New Features in C# 4.0": http://code.msdn.microsoft.com/csharpfuture/Release/ProjectReleases.aspx?ReleaseId=1686
Java kann das bereits. Seit 5.0 funktionieren genauso kovariante Rückgabetypen, und mit den Wildcards kannst du genau das selbe erreichen (http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#Java) wie mit den "in" und "out" Parametern unter .NET 4.0 . Mir persönlich gefällt die Lösung unter .NET allerdings auch besser, als dieser Wildcard-Wirrwarr unter Java. Das sieht streckenweise reichlich hässlich aus.

Sie gehen natürlich syntaktisch etwas andere Wege, aber im Grunde dreht es sich um das selbe Problem: Wenn Y von X erbt, ist nicht automatisch ein Behälter von X automatisch ein geeigneter Behälter von Y.

Auch wenn ein Modellauto und ein PKW sehr eng miteinander verwandt sind, sind deren Aufbewahrungsorte (Garage und Spielzeugkiste) nicht zwingend miteinander verwandt.
Deshalb braucht man da nochmal eine ganz eigene Syntax, weil diese Zusammenhänge über Vererbung nicht ausreichend darstellbar sind.