我试图在Java中调试涉及ClassCastException的问题.为了解决这个问题,我需要知道当我从Object转换为特定类型时会发生什么.任何人都可以向我解释Java转换运算符如何在Java级别和JVM级别上运行?
Mic*_*ers 10
是JLS不够好?
转换转换应用于转换运算符的操作数(第15.16节):操作数表达式的类型必须转换为转换运算符显式命名的类型.转换上下文允许使用:
- 身份转换(§5.1.1)
- 扩展的原始转换(第5.1.2节)
- 缩小的原始转换(第5.1.3节)
- 扩展引用转换(第5.1.5节),可选地后跟未经检查的转换(第5.1.9节)
- 缩小的引用转换(第5.1.6节),可选地后跟未经检查的转换
- 拳击转换(§5.1.7)
- 拆箱转换(第5.1.8节).
实际上,也许这部分更相关:
将编译时引用类型S的值转换为编译时引用类型T的编译时合法性的详细规则如下:
- 如果 S是类类型:
- 如果T是类类型,则为| S | <:| T |,或| T | <:| S |; 否则会发生编译时错误.此外,如果存在的超类型X的 Ť,和超类型ÿ的 小号,使得两个X和 ÿ是可证明不同参数化类型(§4.5),并且的擦除X和 ÿ是相同的,编译时发生错误.
- 如果T是接口类型:
- 如果 小号不是
final类(§8.1.1),然后,如果存在的超类型 X的Ť,和超类型 ÿ的小号,使得两个 X和ÿ是可证明不同参数化类型,那的擦除X和Y 是相同的,发生编译时错误.否则,强制转换在编译时总是合法的(因为即使 S没有实现T,S的子类也可能).- 如果S是一个
final类(第8.1.1节),则S必须实现T,否则会发生编译时错误.- 如果Ť 是一种类型的变量,那么该算法递归地应用,使用上界的Ť代替Ť.
- 如果T是数组类型,则S必须是类
Object,否则会发生编译时错误.- 如果S是接口类型:
- 如果T是数组类型,则T必须实现S,否则会发生编译时错误.
- 如果Ť是一个类型不
final(§8.1.1),然后,如果存在的超类型 X的Ť,和超类型 ÿ的小号,使得两个 X和ÿ是可证明不同参数化类型,那的擦除X和Y 相同,发生编译时错误.否则,强制转换在编译时总是合法的(因为即使 T没有实现S,也可能是T的子类).- 如果T是一个类型
final,那么:
- 如果S不是参数化类型或原始类型,则T必须实现S,并且静态地知道强制转换是正确的,否则会发生编译时错误.
- 否则, S是参数化类型,它是某种泛型类型声明G的调用,或者是对应于泛型类型声明G的原始类型.然后必须存在一个超类型X的 Ť,使得X是的调用ģ,或发生编译时间错误.此外,如果S和X 可证明是不同的参数化类型,则发生编译时错误.
- 如果小号是一种类型的变量,那么该算法递归地应用,使用上界的小号代替 小号.
- 如果 S是数组类型SC [],即SC类型的组件数组:
- 如果T是类类型,那么如果T不是
Object,则发生编译时错误(因为Object是唯一可以为其分配数组的类类型).- 如果T 是接口类型,则会发生编译时错误,除非 T是类型
java.io.Serializable或类型Cloneable,是数组实现的唯一接口.- 如果T 是一个类型变量,那么:
- 如果T的上限是
Object或者类型java.io.Serializable或类型Cloneable,或者通过递归地应用这些规则可以合法地转换为S的类型变量,那么转换是合法的(虽然未经检查).- 如果T的上限是数组类型 TC [],则发生编译时错误,除非通过递归应用这些编译时规则进行转换,可以将类型SC []强制转换为TC [].
- 否则,发生编译时错误.
- 如果T是数组类型TC [],即TC类型的组件数组,则会发生编译时错误,除非满足下列条件之一:
- TC和SC是相同的原始类型.
- TC和 SC是引用类型,类型 SC可以通过递归应用这些编译时规则进行转换来转换为TC.
现在完全清楚,不是吗?:d
换句话说,如果不了解有关您问题的更多详细信息,这是我能做的最好的事情.
类转换神秘化的一个可能原因是,不仅类型必须匹配,而且它们必须由相同的类加载器加载.
您不仅可以转储类型层次结构,还可以转储每个类的类加载器的标识.
这些问题在应用程序风格的环境中并不罕见,其中应用程序代码和基础结构代码是故意隔离的 - 例如,如果系统类意外地包含在应用程序JAR中,您可以在JVM中拥有两个"相同"类的副本,并且生活变得混乱