只定义为返回类型的泛型类型

我正在查看一些用于 GWT 的 GXT 代码,我遇到了泛型(Generics)的这种用法,在 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,每个返回值的例子都是在类级别定义的,或者是在传入的参数中定义的。

64083 次浏览

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

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

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

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

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

但如果不行,你必须输入:

Collections.<String>emptySet();

RpcMap (GXT API 1.2)台的留言很有意思

得到的标题:

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

在这里有一个未实例化的通用参数 <X>也有同样的效果,除了你不必到处说“ Object”。我同意其他海报,这是草率和有点危险。

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

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

这样做的唯一好处是,您不必强制转换这种可以返回任何类型的泛型查找方法的返回值。

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

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

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

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

是的,这很危险,通常情况下,你会这样保护这个代码:

<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);
}

我只是想在 GXT 课上学到同样的东西。具体来说,我试图调用一个具有以下签名的方法:

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

要从代码中调用上面的方法,并让它将 X 强制转换为 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 团队的这种做法相当草率和危险。