模板的类型,如果模板是返回值(Java)

时间:2009-11-12 09:48:37

标签: java templates classcastexception

如果将返回值设置为模板,我想知道模板变量的数据类型是什么。我已经在某个代码中看到了这个,但我不知道它从会话中检索到的值。

public class RequestObject {
    public <T> T getFromSessionMap(String sessionKey) {
        return (T)session.getAttribute(sessionKey);
    }
}

外面的代码是:

MyClassType type = request.getFromSessionMap("abc");

在转换为我的对象时,该行遇到ClassCastException。但是当我添加监视session.getAttribute(“abc”)时,它显示该类型是MyClassType。任何帮助将不胜感激。

显然这个使用模板的特殊代码使得getFromSessionMap的返回变量类型,因此不需要强制转换。这适用于所有情况,但突然在代码的一部分失败了。

4 个答案:

答案 0 :(得分:6)

  

显然这是使用的特殊代码   模板让回归   getFromSessionMap是一个变量类型和   因此无需演员。

从根本上说,必须在获取session.getAttribute(sessionKey)的结果和MyClassType的分配之间的某种类型。 Java语言(和JVM)将不允许某个不是MyClassType实例(或其子类型)的对象分配给MyClassType变量。

无论您如何编写代码,都必须进行类型转换。由于属性(显然)不是MyClassType(或子类型),因此您获得了ClassCastException

所以真正的问题是为什么你没有得到编译错误?答案是@SuppressWarnings("unchecked")!如果您删除了该警告,则会收到此行的“不安全类型转换”错误消息:

return (T) session.getAttribute(sessionKey);

实际上,Java不能对通用类型进行(实际)类型转换。这就是警告/错误消息需要指出的内容。实际上,一旦代码编译完毕,这段代码

public <T> T getFromSessionMap(String sessionKey) {
    return (T)session.getAttribute(sessionKey);
}

实际上与此没有什么不同:

public Object getFromSessionMap(String sessionKey) {
    return session.getAttribute(sessionKey);
}

从技术上讲,这被称为“类型擦除”。

那么类型检查/类型转换实际发生在哪里?答案就在这一行:

MyClassType type = request.getFromSessionMap("abc");

即使你没有在这里编写类型转换,Java编译器生成的代码在将值赋给type之前会进行类型转换。它必须。因为据它所知,它所分配的实例可能是任何对象类型。

其他海报建议在getFromSessionMap中添加一个Class参数。这本身就没有绝对没有。如果您还用以下方法替换方法的主体:

return clazz.cast(session.getAttribute(sessionKey));

您将使该方法实际进行真正的类型检查。但这只会导致ClassCastException被抛到不同的地方。赋值语句仍将执行隐藏类型转换!!

答案 1 :(得分:0)

在问题的示例中,返回类型为T。被删除的类型将Object隐含地T extends Object。实际的强制转换是在调用方法的字节码中执行的(您可以使用javap -c来查看)。

通常,您应该在会话中保持“顶级”对象的数量尽可能小。这样做的好处之一是,不再需要像这样的hacky方法。

答案 2 :(得分:0)

  

任何帮助都会受到赞赏,因为我的代码遇到了ClassCastException。

如果你得到的是ClassCastException,那就意味着你正试图将某些东西投射到某些东西上,就像在下面的代码中一样:

Map session = new HashMap();
session.put("date", "2009-11-12");
Date today = (Date) session.get("date"); // tries to convert String to Date

ClassCastException应该有一个启发性的详细信息,例如“java.lang.String不能转换为java.util.Date”。

答案 3 :(得分:0)

您在方法体中使用了类型转换('(T)session.getAttribute(sessionKey)')。

这意味着您明确地告诉编译器'我绝对确定返回的对象IS-A T并准备好处理错误,如果它不是'

此处您对属性类型的假设不正确,并且您收到了错误消息。所以,一切都是正确的,运行时已经为您提供了不是 IS-A MyClassType的真实属性对象类型。