PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : java generics


michl
2005-11-21, 22:43:11
Hallo!

Habe folgende Frage bzgl. Generics:

import java.util.*;

public class GenericsProblem {

public GenericsProblem() {
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(3,"drei");

String s[] = new String[3];

s[0] = map.get(3);
s[1] = map.get(4);
s[2] = map.get("test");
System.out.println(s[0]+","+s[1]+","+s[2]);
}

public static void main(String[] args) { new GenericsProblem(); }
}

Obwohl als Key für die HashMap nur Integer-Objekte zugelassen sind,
gibt es keinen Compile-Error bei der Zuweisung

s[2] = map.get("test");

Der Grund ist, dass die get-Methode Objects als Parameter erwartet. Bei

map.put("x","y");

bricht der Compiler mit einem Fehler ab. Put() ist type-safe.

Warum ist get() nicht type-safe?

Bin schon gespannt auf eure Antworten.

lg
michl

Trap
2005-11-21, 23:26:05
Ich hab leider auch keine Erklärung, nur ein anderes Beispiel:
ArrayList<T>.toArray() gibt ein Object[] zurück

Senior Sanchez
2005-11-21, 23:58:20
Schlampige Implementierung vom JDK?

Ich kanns mir auch nicht so wirklich erklären, weil unter anderen dafür sind ja generics da.

Monger
2005-11-22, 09:24:55
Das JDK ist noch bei weitem nicht vernünftig durchtypisiert.

#remove in Collections ist afaik auch immer untypisiert. Aus Sicht der Liste ist das ja auch richtig, weil es unwichtig ist von welchem Typ das Objekt ist, was man sowieso nicht haben will. Aber ganz konsequent ist es nicht.

Generics sind ja auch noch sehr jung, ebenso wie Enums. Ich sehe im JDK auch noch ständig "public static final int" Pattern für Konstanten, obwohl Enums dieses Pattern eigentlich ablöst.

Wahrscheinlich liegen die Prioritäten derzeit einfach woanders.

michl
2005-11-23, 20:43:43
Tja, die Typen von Sun haben sich wohl doch etwas dabei gedacht:

Man lese bitte http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf, speziell die Seite 5.

Und dann habe ich die selbe Frage im de.comp.lang.java-Forum gestellt:
http://groups.google.at/group/de.comp.lang.java/browse_frm/thread/66af487ee69a4f43/71b91f6955a5bb6e?lnk=raot&hl=de#71b91f6955a5bb6e

HellHorse
2005-11-25, 23:27:06
[/code]
Obwohl als Key für die HashMap nur Integer-Objekte zugelassen sind,
gibt es keinen Compile-Error bei der Zuweisung

s[2] = map.get("test");

Natürlich, das ist ja auch kein Problem und völlig typsicher. Es wird allerdings halt einfach wie erwartet null zurückgeben.
Gegenbsp:

Object o = new Integer(1);
s[2] = map.get(o);


#remove in Collections ist afaik auch immer untypisiert. Aus Sicht der Liste ist das ja auch richtig, weil es unwichtig ist von welchem Typ das Objekt ist, was man sowieso nicht haben will. Aber ganz konsequent ist es nicht.
Was macht ein statisches Typsystem? Ein statisches Typsystem schränkt den möglichen Code ein, den du schreiben kannst. Idealerweise verhindert es mehr sinnlosen als sinnvollen Code. Hier schränkt es dich so wenig wie möglich ein und es wieder nicht gut. Manchmal frage ich mich echt.

Ja, das Typsystem des Collection Framework hat Probleme, allerdings nicht die von dir angesprochenen sondern unter anderem die optionalen Methoden die das ganze Konzept ad aburdum führen.

Warum ist get() nicht type-safe?

Ist es ja. Siehe oben.

Generics sind ja auch noch sehr jung,
Nein, ganz in Gegenteil. google mal gj und featherweight java.

Ich sehe im JDK auch noch ständig "public static final int" Pattern für Konstanten, obwohl Enums dieses Pattern eigentlich ablöst.
Das ist aber auch BS. Enums ersetzen keine Konstanten.

Senior Sanchez
2005-11-26, 00:59:39
Natürlich, das ist ja auch kein Problem und völlig typsicher. Es wird allerdings halt einfach wie erwartet null zurückgeben.
Gegenbsp:

Object o = new Integer(1);
s[2] = map.get(o);


Was macht ein statisches Typsystem? Ein statisches Typsystem schränkt den möglichen Code ein, den du schreiben kannst. Idealerweise verhindert es mehr sinnlosen als sinnvollen Code. Hier schränkt es dich so wenig wie möglich ein und es wieder nicht gut. Manchmal frage ich mich echt.

Ja, das Typsystem des Collection Framework hat Probleme, allerdings nicht die von dir angesprochenen sondern unter anderem die optionalen Methoden die das ganze Konzept ad aburdum führen.

Ist es ja. Siehe oben.

Nein, ganz in Gegenteil. google mal gj und featherweight java.

Das ist aber auch BS. Enums ersetzen keine Konstanten.

HellHorse, schön dich mal wieder zu sehen und gleich ne Frage *g*

Also was nen statisches Typsystem ist, ist klar und das get() als key nen Object erwartet und es somit funzt, ist ja klar, aber warum ist das so? Warum verlangt das get() nicht eine Referenz des Typs wie die Map initialisiert wurde?

HellHorse
2005-11-26, 13:18:32
HellHorse, schön dich mal wieder zu sehen und gleich ne Frage *g*
Sorry, irgendwie finden die Balken in einem geheimen Kommandobunker gäbe es wichtigeres als in einem Forum zu posten :D

Also was nen statisches Typsystem ist, ist klar und das get() als key nen Object erwartet und es somit funzt, ist ja klar, aber warum ist das so? Warum verlangt das get() nicht eine Referenz des Typs wie die Map initialisiert wurde?
Das ist einer der Punkte an dem das schreiben einer eigenen Hashtable zum Verstäis beträgt. ;)
get() sucht den Wert des Keys k für den (sinngemäss) gilt
o.hashCode() == k.hashCode() && o.equals(k)
Da diese beiden Methoden in Object implementiert ist es egal von welcher Klasse diese Objekte Instanzen sind. Wichtig ist nur dass der Typ des Wertes stimmt und das ist ja sichergestellt.

michl
2005-11-26, 17:33:09
get() sucht den Wert des Keys k für den (sinngemäss) gilt
o.hashCode() == k.hashCode() && o.equals(k)
Da diese beiden Methoden in Object implementiert ist es egal von welcher Klasse diese Objekte Instanzen sind. Wichtig ist nur dass der Typ des Wertes stimmt und das ist ja sichergestellt.
Hallo!

Da ist aber nicht der Grund, warum es so gemacht wurde. Denn das ginge auch, wenn get() typ-orientiert wäre.
Und bitte gib mir mal ein vernünftiges Beispiel, wo man get(a), a instanceof A, braucht, aber nur Objekte von B als Keys existieren.

Der einzige Grund, der mit einleuchtet, ist das Schreiben generischer Methoden mit Hilfe von Wildcards a la '?'.
Solcher Code compiled dann nur, wenn der Parameter von get() Object ist.

HellHorse
2005-11-26, 21:41:57
Da ist aber nicht der Grund, warum es so gemacht wurde.
Wieso, bist du von Sun? Im Moment akzeptiert die Methode den allgemeinsten möglichen Typen. Ich sehe immer das Problem noch nicht.

Und bitte gib mir mal ein vernünftiges Beispiel, wo man get(a), a instanceof A, braucht, aber nur Objekte von B als Keys existieren.
Definier vernünftig. Ich habe ja schon oben Code gepostet der das Problem illustiert. Im Moment fallen mir nur Proxy-Geschichten und Fälle in denen existierender, nicht änderbarer Code das programmieren gegen Interfaces verhindert ein.

Wenn ihr wirklich ein Problem wollt:
public class MapTest {
public static void main(String[] args) {
testMap(new HashMap<Integer, String>());
testMap(new TreeMap<Integer, String>());
}

public static void testMap(Map<Integer, String> map) {
map.put(1, "one");
map.put(2, "two");
System.out.println(map.get("3"));
}

}
Das ist aber IMHO ein Fehler in der Implementation von TreeMap resp. String#compareTo(Object) und nicht Map.

Senior Sanchez
2005-11-27, 17:57:35
Wieso, bist du von Sun? Im Moment akzeptiert die Methode den allgemeinsten möglichen Typen. Ich sehe immer das Problem noch nicht.

Naja, Problem ansich nicht ;) Aber wenn ich halt Generics verwende und entsprechende Typen einfach erwarte bzw. angebe, warum wird dann halt keine richtige Typenprüfung vorgenommen?

Wie ne Hashtabelle funktioniert ist mir klar, aber das müsste doch auch mit den Generics funktionieren, da es ja im Grunde trotzdem Objekte sind und die besitzen nunmal die hashCode() als auch die equals() Funktion.

HellHorse
2005-11-27, 20:20:59
warum wird dann halt keine richtige Typenprüfung vorgenommen?
Weil keine Notwendigkeit besteht?

Senior Sanchez
2005-11-27, 20:49:13
Weil keine Notwendigkeit besteht?

Naja, ok, Fehlermeldung wird nicht geschmissen, aber es wäre ja praktisch wenn man schon gewarnt wird, dass da was nich ganz sauber laufen wird.

Trap
2005-11-27, 20:55:52
Der Java-Compiler kompiliert ja auch keinen dead code, da ist es sehr inkonsequent sowas ohne Warnung zu kompilieren.

Silpion
2005-12-03, 21:36:23
*thread hijack*

Hallo,

ich habe ebenfalls ein Problem mit den Generics. Und zwar habe ich eine Klasse, in der ich bisher die Warnungen nicht wegbekomme und nur unterdrücken kann. Habt ihr eine Ahnung, wie ich den einen Constructor und bei die Methode normalize gestalten kann, so dass keine Warnungen entstehen?

Warnung bei dem Constructor:
"Type safety: The constructor Vector(Collection) belongs to the raw type Vector. References to generic type Vector<E> should be parameterized"

Warnung bei der Methode normalize:
"Type safety: The cast from Object to E is actually checking against the erased type Vertex"

public class Polygon<E extends Vertex> extends java.util.Vector {

public Polygon() {
super();
}

@SuppressWarnings("unchecked")
public Polygon(Collection<? extends E> c) {
super(c);
}

public Polygon(int initialCapacity, int capacityIncrement) {
super(initialCapacity, capacityIncrement);
}

public Polygon(int initialCapacity) {
super(initialCapacity);
}

@SuppressWarnings("unchecked")
public void normalize() {
for (Object vertex : this)
((E)vertex).normalize();
}
}

Silpion
2005-12-03, 22:26:27
public class Polygon<E extends Vertex> extends java.util.Vector<E> {...
*patsch* X-D
Und da hab ich jetzt zwei Stunden dran gesessen. :(