Java Generics:通用类型仅定义为返回类型

Java Generics: Generic type defined as return type only

我正在查看GWT的一些GXT代码,我浏览了泛型的用法,我找不到Java教程中的另一个例子。如果您想查看所有代码,类名是com.extjs.gxt.ui.client.data.BaseModelData。以下是重要的部分:

1
2
3
4
5
6
7
8
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"时,它只转到公共方法签名中的

我试着用以下两个例子来调用这个方法,看看会发生什么:

1
2
3
4
5
6
7
public Date getExpiredate() {
    return  get("expiredate");
}

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

它们编译并且不显示任何错误或警告。我想至少我得做一个演员才能让这个发挥作用。

这是否意味着泛型允许魔法返回值可以是任何东西,并且只会在运行时爆炸?这似乎与仿制药应该做的相反。有人能给我解释一下这个问题,并可能给我一个链接,指向一些能更好地解释这个问题的文档吗?我已经阅读了Sun关于泛型的23页PDF,并且返回值的每个示例都是在类级别定义的,或者是在传入的参数中定义的。


该方法返回您期望的任何类型(在该方法中定义,并且绝对不受限制)。

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

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

我会说:小心使用这样的构造,因为您几乎失去了所有类型的安全性,只获得了不必在每次调用get()时编写显式强制转换的效果。

是的:这几乎就是黑魔法,在运行时爆炸,打破了泛型应该实现什么的整个概念。


类型在方法上声明。这就是"EDOCX1"〔0〕的意思。类型的作用域仅限于方法,并且与特定调用相关。您的测试代码编译的原因是编译器试图确定类型,只有当它不能确定时才会抱怨。在某些情况下,您必须显式。

例如,Collections.emptySet()的声明是

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

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

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

但如果不能,则必须键入:

1
Collections.<String>emptySet();


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

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

要从代码中调用上述方法并使其将x强制转换为字符串,请执行以下操作:

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

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

如果方法与您在同一个类中,我发现必须用"this"来调用它。例如:

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

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


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

1
2
3
public String getExpireDate() {
  return  get("expiredate");
}


有趣的注释,来自rpcmap(gxt api 1.2)

获取标题:

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

其中有一个未实例化的的泛型参数,效果相同,只是不必到处说"object"。我同意另一张海报的说法,这张海报太草率了,有点危险。


是的,这很危险。通常,您会这样保护此代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
<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);
}