Generischer Vektor in abstrakter Klasse ...
MudGuard
- java
Hi,
In einer abstrakten Klasse habe ich folgendes Member samt setter:
class AbstractVectorHolder
{
protected Vector<?> allData;
public void setData(Vector<?> data)
{
allData = data;
}
//... der Rest, der für's Problem irrelevant ist.
}
Dazu eine Instanz einer abgeleiteten Klasse, diese soll eine Methode zum Hinzufügen eines Elements zum Vektor haben:
class OneVectorHolder extends AbstractVectorHolder
{
// public void addRow(WasAuchImmer obj)
// {
// allData.add(obj);
// }
//hier noch mehr kram, der für's Problem irrelevant ist
}
Irgendwo (wo spielt keine Rolle für's Problem) wird dann
OneVectorHolder instanz = new OneVectorHolder();
Vector<WasAuchImmer> data = getVectorOfWasAuchImmer();
instanz.setData(data);
gemacht. Klappt einwandfrei.
Leider kommt jedoch, wenn ich die addRow-Methode reinnehme, die Fehlermeldung
The method add(capture-of ?) in the type Vector<capture-of ?> is not applicable for the arguments (WasAuchImmer)
in der Zeile mit dem allData.add(obj).
Ich hab's mit diversen Casts probiert (z.B: allData.add((Object) obj); ), leider bekomme ich das nicht übersetzt.
Das einzige, was funktioniert, ist
((Vector) allData).add(object);
also ein Cast des Vektors.
Vector<?> sollte doch eigentlich ein Vektor beliebigier Objekte sein, insofern verstehe ich nicht, wieso
allData.add(obj); oder allData.add((Object) obj); nicht funktionieren.
Kann mir das jemand erklären?
Gibt es eine Variante, bei der nur das obj gecastet wird, nicht der ganze Vector?
Oder gar eine Variante ganz ohne Cast?
WasAuchImmer ist dabei irgendeine Klasse, spielt keine Rolle.
cu,
Andreas
Hallo,
vorweg: Ich bin kein Generics-Experte, sondern habe Generics nur das
eine oder andere Mal in einfachen Fällen angewendet.
Dein Problem läßt sich wohl auf Type-Erasure zurückführen. Eigentlich
macht deine Implementierung keinen so wirklich großen Sinn, wenn du
mich fragst.
class AbstractVectorHolder
{
protected Vector<?> allData;public void setData(Vector<?> data)
{
allData = data;
}//... der Rest, der für's Problem irrelevant ist.
}
Hier sagst du, daß die Klasse einen typisierten Vector mit unspezifiziertem
Typ aufnehmen kann. Blöderweise ist der Typ zur Compile-Zeit nicht
bekannt. Ergo könntest du hier jetzt z.B. keine get-Methode zur
Klasse hinzufügen, die ein Element aus dem Vector zurückliefert, einfach
weil der Typ nicht bekannt ist.
Zur Laufzeit wäre er das natürlich. Aber Generics sind nun mal eben
genau dafür da, daß sie zur Compile-Zeit sicher sind. Durch einen
Cast, wie du ihn unten probierst, umgehst du diese Sicherheit natürlich
wieder. Bei einem Cast verlässt sich der Compiler aber schlichtweg
auf deine Weisheit und fragt nicht weiter nach. Mit einem Cast geht
alles. Das aber nur am Rande.
Mit deiner Klasse hast du die Information über den Typ zur Compile-Zeit
jedenfalls weggeworfen und wirst ihn auch nicht mehr erhalten können.
class OneVectorHolder extends AbstractVectorHolder
{
// public void addRow(WasAuchImmer obj)
// {
// allData.add(obj);
// }//hier noch mehr kram, der für's Problem irrelevant ist
}
Wenn du hier jetzt versuchst ein WasAuchImmer-Objekt in den Vector zu
schreiben, geht das im Grunde deshalb nicht, weil der Vector keinen
konkreten Typ hat. Er hat einen unbekannten Typ. Deshalb kannst du auf
diese Weise auch kein einziges(!) Objekt in den Vector ablegen. Denn
damit würdest du mit der Typsicherheit zur Compile-Zeit brechen. Da
der Compiler nicht weiß, welchen Typ der Vector hat, könntest du alles
mögliche reinstecken, wenn es keinen Compile-Fehler geben würde. Und
bei der nächsten Abfrage (von außerhalb des AbstractVectorHolder-
Objekts, s.u.) würde bei falschem Typ (z.B. String) eine ClassCastException
geworfen werden. Aber das wäre genau das Gegenteil von Compile-Zeit-
Sicherheit. :)
Irgendwo (wo spielt keine Rolle für's Problem) wird dann
OneVectorHolder instanz = new OneVectorHolder();
Vector<WasAuchImmer> data = getVectorOfWasAuchImmer();
instanz.setData(data);gemacht. Klappt einwandfrei.
Das geht. Du kannst auch prima sowas wie data.add(new WasAuchImmer())
aufrufen. In diesem Scope ist nämlich zur Compile-Zeit(!) bekannt, daß
"data" vom Typ Vector<WasAuchImmer> ist. Im Scope von OneVectorHolder
wurde der Type durch ? gelöscht und ist (zur Compile-Zeit) nicht mehr
bekannt.
Ich hab's mit diversen Casts probiert (z.B: allData.add((Object) obj); ), leider bekomme ich das nicht übersetzt.
Das einzige, was funktioniert, ist
((Vector) allData).add(object);
also ein Cast des Vektors.
Ja, weil du damit aus dem Objekt quasi ein Vector<Object>-Objekt machst.
Da kannst du natürlich alles reinstecken, was von Object abgeleitet ist.
(Also alles.) Wenn du allerdings z.B. ein new Object() reinstecken
würdest, würde ein nachfolgender Aufruf wie "allData.get(5)" zu einer
ClassCastException führen, weil in der (typisierten) get-Methoden eben
intern einen Type-Cast auf "WasAuchImmer" macht.
Vector<?> sollte doch eigentlich ein Vektor beliebigier Objekte sein, insofern verstehe ich nicht, wieso
allData.add(obj); oder allData.add((Object) obj); nicht funktionieren.
Nein, ein Vector<Object> wäre ein Vector beliebiger Objekte. Blöderweise
kriegst du dann bei z.B. get() allerdings auch nur einen Object-Typ
zurück, hast also nur auf die Methoden Zugriff, die in Object definiert
sind.
Gibt es eine Variante, bei der nur das obj gecastet wird, nicht der ganze Vector?
Oder gar eine Variante ganz ohne Cast?
Was willst du eigentlich genau erreichen?
Lies dir mal den Generics-Abschnitt aus 'Java ist auch eine Insel' durch.
Da ist das eigentlich recht gut erklärt. (Zumindest um einen groben
Eindruck zu erhalten.)
Würd mich aber tatsächlich interessieren, was du hier vorhattest.
Vielleicht läßt sich ja gemeinsam eine Lösung finden.
Gruß
Slyh
Hi,
vorweg: Ich bin kein Generics-Experte, sondern habe Generics nur das
eine oder andere Mal in einfachen Fällen angewendet.Dein Problem läßt sich wohl auf Type-Erasure zurückführen. Eigentlich
macht deine Implementierung keinen so wirklich großen Sinn, wenn du
mich fragst.
Naja ...
Was ich eigentlich mache, sind z.B. abstrakte Klassen, die z.B. von AbstractTableModel oder ähnlichem abgeleitet sind und diese um gemeinsame Funktionalität erweitern. Eine dieser Erweiterungen ist eben, daß sie den Vektor mit den Daten enthält und darauf einige Operationen zur Verfügung stellt.
Andere Funktionalitäten wie eben das Hinzufügen _eines_ konkreten Datenobjekts (im Beispiel war es WasAuchImmer) zum Vektor, also mein addRow(WasAuchImmmer was), die ich nicht überall brauche (die meisten der Tabellen bekommen komplett neue Daten und bleiben von der Datenmenge her unverändert, bis die Daten komplett ersetzt werden, dort werden nie einzelne Datensätze hinzugefügt), wollte ich jetzt in der instanzierbaren Klasse hinzufügen.
Lies dir mal den Generics-Abschnitt aus 'Java ist auch eine Insel' durch.
Werde ich machen.
Würd mich aber tatsächlich interessieren, was du hier vorhattest.
Vielleicht läßt sich ja gemeinsam eine Lösung finden.
Eine der Lösungen wäre vermutlich, den Vektor in der abstrakten Klasse nicht zu typisieren. Oder auf Vector<Object> zu gehen.
Mal sehen, was ich da mache.
cu,
Andreas