71

我正在查看 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 中点击“转到声明”时,它只是转到<X>公共方法签名中的。

我尝试使用以下两个示例调用此方法,看看会发生什么:

public Date getExpiredate() {
    return  get("expiredate");
}

public String getSubject() {
    return  get("subject");
}

它们编译并且不显示错误或警告。我认为至少我必须做一个演员才能让它发挥作用。

这是否意味着泛型允许一个神奇的返回值,它可以是任何东西,并且会在运行时爆炸?这似乎与泛型应该做的背道而驰。任何人都可以向我解释这一点,并可能给我一个链接到一些解释这个更好一点的文档吗?我已经阅读了 Sun 关于泛型的 23 页 pdf,每个返回值示例都是在类级别定义的,或者在传入的参数之一中定义。

4

6 回答 6

57

该方法返回您期望的任何类型(<X>在方法中定义并且绝对无界)。

这是非常非常危险的,因为没有规定返回类型实际上与返回值匹配。

这样做的唯一优点是您不必强制转换可以返回任何类型的通用查找方法的返回值。

我会说:小心使用这样的结构,因为你几乎失去了所有类型安全性,并且只获得了你不必在每次调用get().

是的:这几乎是一种黑魔法,它在运行时爆炸并打破了泛型应该实现的整个想法。

于 2008-12-03T22:05:41.700 回答
40

类型在方法上声明。就是“ <X>”的意思。然后类型的范围仅限于方法,并且与特定调用相关。您的测试代码编译的原因是编译器试图确定类型,并且只有在不能确定时才会抱怨。在某些情况下,您必须明确。

例如,声明Collections.emptySet()

public static final <T> Set<T> emptySet()

在这种情况下,编译器可以猜测:

Set<String> s = Collections.emptySet();

但如果不能,您必须输入:

Collections.<String>emptySet();
于 2008-12-03T22:02:53.643 回答
5

我只是想用 GXT 类来解决同样的问题。具体来说,我试图调用具有以下签名的方法:

class Model {
    public <X> X get(String property) { ... }
}

要从您的代码中调用上述方法并将 X 转换为字符串,我执行以下操作:

public String myMethod(Data data) {
    Model model = new Model(data);
    return model.<String>get("status");
}

上面的代码将调用 get 方法并告诉它 X 返回的类型应该作为字符串返回。

在方法与您在同一个类中的情况下,我发现我必须用“this.”来调用它。例如:

this.<String>get("status");

正如其他人所说,这对 GXT 团队来说是相当草率和危险的。

于 2011-09-27T14:38:59.480 回答
2

有趣的注释,来自RpcMap (GXT API 1.2)

获取标题:

public java.lang.Object get(java.lang.Object key)

在那里有一个未实例化的通用参数<X>具有相同的效果,只是您不必到处都说“对象”。我同意另一张海报,这很草率而且有点危险。

于 2008-12-03T22:05:02.607 回答
2

BaseModelData 在编译时会引发未经检查的警告,因为它是不安全的。像这样使用,您的代码将在运行时抛出 ClassCastException,即使它本身没有任何警告。

public String getExpireDate() {
  return  get("expiredate");
}
于 2008-12-03T22:17:24.003 回答
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);
}
于 2009-02-21T13:02:00.510 回答