Java 泛型:泛型类型仅定义为返回类型
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/338887/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java Generics: Generic type defined as return type only
提问by Jason Tholstrup
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:
我正在查看 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
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.
X
在类中或层次结构中的任何其他地方都没有定义,当我在 Eclipse 中点击“转到声明”时,它只会转到<X>
公共方法签名中的 。
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.
这是否意味着泛型允许一个神奇的返回值,它可以是任何东西并且只会在运行时爆炸?这似乎与泛型应该做的事情背道而驰。任何人都可以向我解释这一点,并可能给我一个链接到一些更好地解释这一点的文档?我已经浏览了 Sun 关于泛型的 23 页 pdf,并且返回值的每个示例都是在类级别或在传入的参数之一中定义的。
采纳答案by Joachim Sauer
The method returns a type of whatever you expect it to be (<X>
is defined in the method and is absolutely unbounded).
该方法返回您期望的任何类型(<X>
在方法中定义并且绝对无界)。
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()
.
我会说:小心使用这样的结构,因为你几乎失去了所有的类型安全性,而只是你不必在每次调用get()
.
And yes: this pretty much is black magic that blows up at runtime and breaks the entire idea of what generics should achieve.
是的:这几乎是黑魔法,它在运行时爆炸并破坏了泛型应该实现的整个想法。
回答by sblundy
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.
类型在方法上声明。这就是“ <X>
”的意思。该类型的范围仅限于该方法并且与特定调用相关。您的测试代码编译的原因是编译器尝试确定类型并且只有在不能确定时才会抱怨。在某些情况下,您必须明确。
For example, the declaration for Collections.emptySet()
is
例如,对于该声明Collections.emptySet()
是
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();
回答by Rich
Interesting note, from RpcMap (GXT API 1.2)
有趣的笔记,来自RpcMap (GXT API 1.2)
get's header:
get 的标题:
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.
<X>
在那里有一个未实例化的通用参数具有相同的效果,除了您不必到处都说“对象”。我同意另一张海报,这很草率,有点危险。
回答by erickson
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.
BaseModelData 在编译时会引发未经检查的警告,因为它不安全。像这样使用,您的代码将在运行时抛出 ClassCastException,即使它本身没有任何警告。
public String getExpireDate() {
return get("expiredate");
}
回答by paulmurray
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);
}
回答by Kyrra
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:
我只是想用 GXT 课程找出同样的事情。具体来说,我试图调用具有以下签名的方法:
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:
要从您的代码调用上述方法并将 X 转换为字符串,我执行以下操作:
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.
上面的代码将调用 get 方法并告诉它 X 返回的类型应该作为 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.”来调用它。例如:
this.<String>get("status");
As others have said, this is rather sloppy and dangerous by the GXT team.
正如其他人所说,GXT 团队这样做相当草率和危险。