我正在查看GWT的一些GXT代码,我遇到了泛型的这种使用,我在Java教程中找不到另一个例子。如果要查看所有代码,则类名为com.extjs.gxt.ui.client.data.BaseModelData
。以下是重要部分:
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
在类中或层次结构中的任何地方都没有定义,当我在eclipse中点击“go to declaration”时,它只会转到公共方法签名中的<X>
。
我尝试使用以下两个示例来调用此方法,以了解会发生什么:
public Date getExpiredate() {
return get("expiredate");
}
public String getSubject() {
return get("subject");
}
他们编译并显示没有错误或警告。我认为至少我必须做一个演员才能让它发挥作用。
这是否意味着Generics允许魔法返回值可以是任何东西,并且会在运行时爆炸?这似乎与泛型应该做的事情相反。任何人都可以向我解释这一点,并可能给我一些链接到一些文档,解释这一点好一点?我已经浏览了Sun关于泛型的23页pdf,并且每个返回值的例子都是在类级别定义的,或者是传入的参数之一。
答案 0 :(得分:53)
该方法返回一种你期望的类型(<X>
在方法中定义并且绝对无限制。)
这非常非常危险,因为没有规定返回类型实际上与返回值匹配。
这样做的唯一好处就是您不必转换可以返回任何类型的通用查找方法的返回值。
我会说:小心使用这样的结构,因为你几乎失去了所有的类型安全性,只是在每次调用get()
时都不需要写一个显式的强制转换。
是的:这几乎是黑魔法在运行时爆炸并打破了泛型应该实现的全部想法。
答案 1 :(得分:39)
在方法上声明类型。这就是“<X>
”的意思。该类型的范围仅限于方法,并且与特定调用相关。您的测试代码编译的原因是编译器尝试确定类型,并且只有在它不能的情况下才会抱怨。有些情况下你必须明确。
例如,Collections.emptySet()
的声明是
public static final <T> Set<T> emptySet()
在这种情况下,编译器可以猜测:
Set<String> s = Collections.emptySet();
但如果不能,则必须输入:
Collections.<String>emptySet();
答案 2 :(得分:5)
我只是试图用GXT类找出同样的东西。具体来说,我试图调用一个签名为:
的方法class Model {
public <X> X get(String property) { ... }
}
要从代码中调用上述方法并将其转换为String,请执行以下操作:
public String myMethod(Data data) {
Model model = new Model(data);
return model.<String>get("status");
}
上面的代码将调用get方法并告诉它X返回的类型应该作为String返回。
如果该方法与您在同一类中,我发现我必须用“this”来调用它。例如:
this.<String>get("status");
正如其他人所说,这对GXT团队来说是相当草率和危险的。
答案 3 :(得分:2)
有趣的提示,来自RpcMap (GXT API 1.2)
获取标题:
public java.lang.Object get(java.lang.Object key)
在其中具有未实例化的<X>
的泛型参数具有相同的效果,除了您不必在整个地方说“对象”。我同意另一张海报,这是草率的,有点危险。
答案 4 :(得分:2)
BaseModelData在编译时会引发未经检查的警告,因为它不安全。像这样使用,你的代码会在运行时抛出一个ClassCastException,即使它本身没有任何警告。
public String getExpireDate() {
return get("expiredate");
}
答案 5 :(得分:0)
是的,这很危险。通常,您可以像这样保护此代码:
<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);
}