1

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

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

这个外面的代码是:

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

该行在投射到我的对象时遇到 ClassCastException。但是当我添加到 watch session.getAttribute("abc") 时,它显示类型是 MyClassType。任何帮助,将不胜感激。

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

4

4 回答 4

6

显然,这个使用模板的特殊代码使 getFromSessionMap 的返回成为变量类型,因此不需要强制转换。

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

无论您如何编写代码,都必须进行类型转换。而且由于该属性(显然)不是 a 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. 它必须。因为据它所知,它分配的实例可以是任何对象类型。

其他发帖人建议将 Class 参数添加到getFromSessionMap. 就其本身而言,这完全没有任何作用。如果您还将方法的主体替换为:

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

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

于 2009-11-12T10:23:41.300 回答
0

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

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

于 2009-11-12T09:58:33.430 回答
0

任何帮助将不胜感激,因为我的代码遇到 ClassCastException。

如果你得到 a 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”。

于 2009-11-12T10:03:22.067 回答
0

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

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

在这里,您对属性类型的假设不正确,并且出现错误。因此,一切都是正确的,并且运行时已经为您提供了不是IS-A MyClassType 的真实属性对象类型。

于 2009-11-12T10:21:55.463 回答