Java 泛型:泛型类型仅定义为返回类型

发布于 2024-07-09 04:15:52 字数 1065 浏览 11 评论 0原文

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

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

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

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

它们编译并没有显示任何错误或警告。 我认为至少我必须进行演员阵容才能使其发挥作用。

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

I'm looking at some GXT code for GWT and I ran across this use of Generics that I can't find another example of in the Java tutorials. The class name is com.extjs.gxt.ui.client.data.BaseModelData if you want to look at all of the code. Here are the important parts:

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 is defined nowhere else in the class or anywhere in the hierarchy, and when I hit "go to declaration" in eclipse it just goes to the <X> in the public method signature.

I've tried to call this method with the following two examples to see what happens:

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

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

They compile and show no errors or warnings. I would think at the very least I would have to do a cast to get this to work.

Does this mean that Generics allow a magic return value that can be anything and will just blow up at runtime? This seems counter to what generics are supposed to do. Can anyone explain this to me and possibly give me a link to some documentation that explains this a little better? I've went through Sun's 23 page pdf on generics and every example of a return value is defined either at the class level or is in one of the parameters passed in.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

甜宝宝 2024-07-16 04:15:52

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

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

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

我想说:请谨慎使用此类构造,因为您会失去几乎所有类型安全性,而只会获得不必在每次调用 get() 时都编写显式强制转换的好处。

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

The method returns a type of whatever you expect it to be (<X> is defined in the method and is absolutely unbounded).

This is very, very dangerous as no provision is made that the return type actually matches the returned value.

The only advantage this has is that you don't have to cast the return value of such generic lookup methods that can return any type.

I'd say: use such constructs with care, because you lose pretty much all type-safety and gain only that you don't have to write an explicit cast at each call to get().

And yes: this pretty much is black magic that blows up at runtime and breaks the entire idea of what generics should achieve.

清引 2024-07-16 04:15:52

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

例如, 的声明Collections.emptySet()

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

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

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

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

Collections.<String>emptySet();

The type is declared on the method. That's that "<X>" means. The type is scoped then to just the method and is relevant to a particular call. The reason your test code compiles is that the compiler tries to determine the type and will complain only if it can't. There are cases where you have to be explicit.

For example, the declaration for Collections.emptySet() is

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

In this case, the compiler can guess:

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

But if it can't, you must type:

Collections.<String>emptySet();
零崎曲识 2024-07-16 04:15:52

我只是想通过 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 方法并告诉它返回的类型by X 应作为字符串返回。

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

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

正如其他人所说,GXT 团队的做法相当草率且危险。

I was just trying to figure out the same thing with a GXT class. Specifically I was trying to call a method with the signature of:

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

To call the above method from your code and have it cast X to a String I do the following:

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

The above code will call the get method and tell it that the type being returned by X should be returned as a String.

In the case where the method is in the same class as you, I've found that I have to call it with a "this.". For example:

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

As others have said, this is rather sloppy and dangerous by the GXT team.

慈悲佛祖 2024-07-16 04:15:52

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

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

BaseModelData raises unchecked warnings when compiled, because it is unsafe. Used like this, your code will throw a ClassCastException at runtime, even though it doesn't have any warnings itself.

public String getExpireDate() {
  return  get("expiredate");
}
无风消散 2024-07-16 04:15:52

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

get 的标头:

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

其中未实例化的通用参数 具有相同的效果,除非您不必说“对象”无处不在。 我同意另一张海报的观点,这很草率而且有点危险。

Interesting note, from RpcMap (GXT API 1.2)

get's header:

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

Having a generic parameter of <X> in there that's uninstantiated has the same effect, except you don't have to say "Object" all over the place. I agree with the other poster, this is sloppy and a bit dangerous.

痴情 2024-07-16 04:15:52

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

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

Yes, this is dangerous. Normally, you'd protect this code like so:

<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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文