Ich schaue mir einen GXT-Code für GWT an und bin auf diese Verwendung von Generika gestoßen, für die ich in den Java-Tutorials kein weiteres Beispiel finden kann. Der Klassenname lautet, com.extjs.gxt.ui.client.data.BaseModelData
wenn Sie den gesamten Code anzeigen möchten. Hier sind die wichtigen Teile:
private RpcMap map;
public <X> X get(String property) {
if (allowNestedValues && NestedModelUtil.isNestedProperty(property)) {
return (X)NestedModelUtil.getNestedValue(this, property);
}
return map == null ? null : (X) map.get(property);
}
X
wird nirgendwo anders in der Klasse oder irgendwo in der Hierarchie definiert, und wenn ich in Eclipse auf "Gehe zur Deklaration" drücke, gehe ich einfach zur <X>
Signatur in der öffentlichen Methode.
Ich habe versucht, diese Methode mit den folgenden zwei Beispielen aufzurufen, um zu sehen, was passiert:
public Date getExpiredate() {
return get("expiredate");
}
public String getSubject() {
return get("subject");
}
Sie kompilieren und zeigen keine Fehler oder Warnungen. Ich würde zumindest denken, dass ich eine Besetzung machen müsste, um dies zum Laufen zu bringen.
Bedeutet dies, dass Generika einen magischen Rückgabewert zulassen, der alles sein kann und nur zur Laufzeit explodiert? Dies scheint dem zu widersprechen, was Generika tun sollen. Kann mir jemand dies erklären und mir möglicherweise einen Link zu einer Dokumentation geben, die dies etwas besser erklärt? Ich habe das 23-seitige PDF von Sun zu Generika durchgesehen und jedes Beispiel für einen Rückgabewert wird entweder auf Klassenebene oder in einem der übergebenen Parameter definiert.
ObjectInputStream::readObject
.Antworten:
Die Methode gibt einen Typ von dem zurück, was Sie erwarten (
<X>
ist in der Methode definiert und absolut unbegrenzt).Dies ist sehr, sehr gefährlich, da nicht vorgesehen ist, dass der Rückgabetyp tatsächlich mit dem zurückgegebenen Wert übereinstimmt.
Der einzige Vorteil besteht darin, dass Sie den Rückgabewert solcher generischen Suchmethoden, die einen beliebigen Typ zurückgeben können, nicht umwandeln müssen.
Ich würde sagen: Verwenden Sie solche Konstrukte mit Vorsicht, da Sie so gut wie alle Typensicherheit verlieren und nur gewinnen, dass Sie nicht bei jedem Aufruf eine explizite Besetzung schreiben müssen
get()
.Und ja: Das ist so ziemlich schwarze Magie, die zur Laufzeit explodiert und die gesamte Idee bricht, was Generika erreichen sollen.
quelle
Der Typ wird in der Methode deklariert. Das
<X>
heißt " ". Der Typ ist dann nur auf die Methode beschränkt und für einen bestimmten Aufruf relevant. Der Grund, warum Ihr Testcode kompiliert wird, ist, dass der Compiler versucht, den Typ zu bestimmen, und sich nur beschwert, wenn dies nicht möglich ist. Es gibt Fälle, in denen Sie explizit sein müssen.Zum Beispiel für die Erklärung
Collections.emptySet()
istpublic static final <T> Set<T> emptySet()
In diesem Fall kann der Compiler Folgendes erraten:
Wenn dies nicht möglich ist, müssen Sie Folgendes eingeben:
quelle
Ich habe nur versucht, dasselbe mit einer GXT-Klasse herauszufinden. Insbesondere habe ich versucht, eine Methode mit der Signatur aufzurufen:
class Model { public <X> X get(String property) { ... } }
Um die obige Methode aus Ihrem Code aufzurufen und X in einen String umwandeln zu lassen, gehe ich wie folgt vor:
public String myMethod(Data data) { Model model = new Model(data); return model.<String>get("status"); }
Der obige Code ruft die get-Methode auf und teilt ihr mit, dass der von X zurückgegebene Typ als String zurückgegeben werden soll.
In dem Fall, in dem sich die Methode in derselben Klasse wie Sie befindet, habe ich festgestellt, dass ich sie mit einem "this" aufrufen muss. Zum Beispiel:
this.<String>get("status");
Wie andere gesagt haben, ist dies für das GXT-Team ziemlich schlampig und gefährlich.
quelle
BaseModelData löst beim Kompilieren ungeprüfte Warnungen aus, da es unsicher ist. Bei dieser Verwendung löst Ihr Code zur Laufzeit eine ClassCastException aus, obwohl er selbst keine Warnungen enthält.
public String getExpireDate() { return get("expiredate"); }
quelle
Interessanter Hinweis von RpcMap (GXT API 1.2)
get's Header:
public java.lang.Object get(java.lang.Object key)
Ein generischer Parameter von
<X>
dort, der nicht fundiert ist, hat den gleichen Effekt, außer dass Sie nicht überall "Objekt" sagen müssen. Ich stimme dem anderen Poster zu, das ist schlampig und ein bisschen gefährlich.quelle
Ja, das ist gefährlich. Normalerweise würden Sie diesen Code folgendermaßen schützen:
<X> getProperty(String name, Class<X> clazz) { X foo = (X) whatever(name); assert clazz.isAssignableFrom(foo); return foo; } String getString(String name) { return getProperty(name, String.class); } int getInt(String name) { return getProperty(name, Integer.class); }
quelle