模板的类型(如果模板是返回值)(Java)
我想知道如果返回设置为模板,模板变量的数据类型是什么。我在某处的代码中看到了这一点,但我不知道它将从会话中检索到的值转换到哪里。
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 返回变量类型,因此不需要强制转换。这适用于所有情况,但突然在代码的一部分失败了。
I was wondering what is the data type of the template variable if the return is set to a template. I have seen this in a code somewhere but I do not know where does it cast the value retrieved from the session.
public class RequestObject {
public <T> T getFromSessionMap(String sessionKey) {
return (T)session.getAttribute(sessionKey);
}
}
The code for this outside is:
MyClassType type = request.getFromSessionMap("abc");
The line encounters ClassCastException when casting to my object. But when I add to watch session.getAttribute("abc"), it shows that the type is MyClassType. Any help would be appreciated.
Apparently this special code for using template makes the return of getFromSessionMap a variable type and hence no need for a cast. This works on all cases but suddenly it failed in one part of the code.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
从根本上讲,在获取
session.getAttribute(sessionKey)
的结果和分配给MyClassType
之间必须进行类型转换。 Java 语言(和 JVM)不允许将某些不是MyClassType
实例(或其子类型)的对象分配给MyClassType变量。
无论您如何编写代码,都必须进行类型转换。由于该属性(显然)不是
MyClassType
(或子类型),因此您将收到ClassCastException
。所以真正的问题是为什么你没有收到编译错误?答案是
@SuppressWarnings("unchecked")
!如果删除该警告,您将收到此行的“不安全类型转换”错误消息:事实上,Java 无法对泛型类型执行(真实)类型转换。这就是警告/错误消息要指出的内容。事实上,一旦代码被编译,这段代码的
含义实际上与此没有什么不同:
从技术上讲,这称为“类型擦除”。
那么类型检查/类型转换实际发生在哪里?答案就在这一行:
即使您没有在这里编写类型转换,Java 编译器生成的代码也会在将值分配给
type
之前进行类型转换。必须如此。因为据它所知,它分配的实例可以是任何对象类型。其他发帖者建议向
getFromSessionMap
添加一个 Class 参数。就其本身而言,这绝对没有任何作用。如果您还将方法的主体替换为:,您将导致该方法实际上执行真正的类型检查。但这只会导致
ClassCastException
在不同的地方抛出。并且赋值语句仍然会进行隐藏类型转换!!Fundamentally, there has to be a typecast somewhere between getting the result of
session.getAttribute(sessionKey)
and the assignment toMyClassType
. The Java language (and the JVM) will not allow some object that is not aMyClassType
instance (or a subtype thereof) to be assigned to aMyClassType
variable.No matter how you write the code, a typecast has to occur. And since the attribute (apparently) is not a
MyClassType
(or subtype), you are getting aClassCastException
.So the real question is why aren't you getting a compilation error? And the answer is the
@SuppressWarnings("unchecked")
! If you removed that warning, you would get an "unsafe type conversion" error message for this line:In truth, Java cannot do a (real) type cast to a generic type. And that is what the warning / error message is there to point out. In fact, once the code has been compiled, this code
is actually no different in meaning from this:
Technically speaking this is called "type erasure".
So where is the type checking / typecast actually occurring? The answer is in this line:
Even though you haven't written a typecast here, the code generated by the Java compiler does a typecast before assigning the value to
type
. It has to. Because as far as it knows, the instance it is assigning could be any object type.Other posters have suggested adding a Class argument to
getFromSessionMap
. By itself this does absolutely nothing. If you also replace the body of the method with:you will cause the method to actually do a real type check. But this only cause
ClassCastException
to be thrown at a different place. And the assignment statement will still do a hidden type cast!!在问题的示例中,返回类型为
T
。擦除的类型将是Object
,隐式地为T extends Object
。实际的转换是在调用方法的字节码中执行的(您可以使用 javap -c 来查看)。一般来说,您应该使会话中“顶级”对象的数量尽可能小。这样做的好处之一是不再需要像这样的黑客方法。
In the question's example, the return type is
T
. The erased type will beObject
as, implicitly,T extends Object
. The actual cast is performed in the bytecode of the calling method (you can usejavap -c
to see that).Generally, you should keep the number of "top-level" objects in sessions as small as possible. One of the benefits of doing that, is there is no longer a need for hacky methods like these.
如果您收到
ClassCastException
,这意味着您正在尝试将某些内容转换为它不是的内容,如以下代码所示:ClassCastException
应该具有启发性详细消息,例如“java.lang.String 无法转换为 java.util.Date”。If you're getting a
ClassCastException
, that means you're trying to cast something into something it isn't, like in the following code:The
ClassCastException
should have an enlightening detail message, like "java.lang.String cannot be cast to java.util.Date".您可以在方法主体中使用类型转换('(T)session.getAttribute(sessionKey)')。
这意味着您明确地对编译器说“我绝对确定返回的对象是 IS-A T,如果不是,则准备好处理错误”。
在这里,您对属性类型的假设不正确,并且出现错误。因此,一切都是正确的,运行时已经为您提供了真正的属性对象类型,而不是 IS-A MyClassType。
You use type cast within the method body ('(T)session.getAttribute(sessionKey)').
That means that you explicitly say to compiler 'I'm absolutely sure that returned object IS-A T and ready to handle error if it is not'.
Here your assumption about attribute type was incorrect and you got an error. So, everything is correct and runtime already provides you with the real attribute object type that is not IS-A MyClassType.