简体   繁体   English

Java强制转换操作符如何工作?

[英]How does the Java cast operator work?

I am trying to debug an issue involving a ClassCastException in Java. 我试图在Java中调试涉及ClassCastException的问题。 In the interest of solving the issue I need to know what is going on when I cast from Object to a specific type. 为了解决这个问题,我需要知道当我从Object转换为特定类型时会发生什么。 Can anyone explain to me how the Java cast operator works at the Java level and the JVM level? 任何人都可以向我解释Java转换运算符如何在Java级别和JVM级别上运行?

Is the JLS good enough? JLS足够好吗?

Casting conversion is applied to the operand of a cast operator (§15.16): the type of the operand expression must be converted to the type explicitly named by the cast operator. 转换转换应用于转换运算符的操作数(第15.16节):操作数表达式的类型必须转换为转换运算符显式命名的类型。 Casting contexts allow the use of: 转换上下文允许使用:

  • an identity conversion (§5.1.1) 身份转换(§5.1.1)
  • a widening primitive conversion (§5.1.2) 扩展的原始转换(第5.1.2节)
  • a narrowing primitive conversion (§5.1.3) 缩小的原始转换(第5.1.3节)
  • a widening reference conversion (§5.1.5) optionally followed by an unchecked conversion (§5.1.9) 扩展引用转换(第5.1.5节),可选地后跟未经检查的转换(第5.1.9节)
  • a narrowing reference conversion (§5.1.6) optionally followed by an unchecked conversion 缩小的引用转换(第5.1.6节),可选地后跟未经检查的转换
  • a boxing conversion (§5.1.7) 拳击转换(§5.1.7)
  • an unboxing conversion (§5.1.8). 拆箱转换(第5.1.8节)。

Actually, maybe this part is more relevant: 实际上,也许这部分更相关:

The detailed rules for compile-time legality of a casting conversion of a value of compile-time reference type S to a compile-time reference type T are as follows: 将编译时引用类型S的值转换为编译时引用类型T的编译时合法性的详细规则如下:

  • If S is a class type: 如果S是类类型:
    • If T is a class type, then either | 如果T是类类型,则为| S | S | <: | <:| T |, or | T |,或| T | T | <: | <:| S |; S |; otherwise a compile-time error occurs. 否则会发生编译时错误。 Furthermore, if there exists a supertype X of T , and a supertype Y of S , such that both X and Y are provably distinct parameterized types (§4.5), and that the erasures of X and Y are the same, a compile-time error occurs. 此外,如果存在T的超类型XS的超类型Y ,使得XY都可以证明是不同的参数化类型(§4.5),并且XY的擦除是相同的,则编译时发生错误。
    • If T is an interface type: 如果T是接口类型:

      • If S is not a final class (§8.1.1), then, if there exists a supertype X of T , and a supertype Y of S , such that both X and Y are provably distinct parameterized types, and that the erasures of X and Y are the same, a compile-time error occurs. 如果S不是final类(第8.1.1节),那么,如果存在T的超类型XS的超类型Y ,那么XY都可以证明是不同的参数化类型,并且X的擦除和Y相同,发生编译时错误。 Otherwise, the cast is always legal at compile time (because even if S does not implement T , a subclass of S might). 否则,强制转换在编译时总是合法的(因为即使S没有实现TS的子类也可能)。
      • If S is a final class (§8.1.1), then S must implement T , or a compile-time error occurs. 如果Sfinal类(第8.1.1节),那么S必须实现T ,否则会发生编译时错误。

    • If T is a type variable, then this algorithm is applied recursively, using the upper bound of T in place of T . 如果T是一个类型变量,则递归地应用该算法,使用T的上限代替T.
    • If T is an array type, then S must be the class Object , or a compile-time error occurs. 如果T是数组类型,则S必须是Object类,否则会发生编译时错误。
  • If S is an interface type: 如果S是接口类型:
    • If T is an array type, then T must implement S , or a compile-time error occurs. 如果T是数组类型,则T必须实现S ,否则会发生编译时错误。
    • If T is a type that is not final (§8.1.1), then if there exists a supertype X of T , and a supertype Y of S , such that both X and Y are provably distinct parameterized types, and that the erasures of X and Y are the same, a compile-time error occurs. 如果T是一个非final的类型(§8.1.1),那么如果存在T的超类型XS的超类型Y ,那么XY都可以证明是不同的参数化类型,并且XY相同,发生编译时错误。 Otherwise, the cast is always legal at compile time (because even if T does not implement S , a subclass of T might). 否则,强制转换在编译时总是合法的(因为即使T没有实现S ,也可能是T的子类)。
    • If T is a type that is final , then: 如果Tfinal的类型,那么:
      • If S is not a parameterized type or a raw type, then T must implement S , and the cast is statically known to be correct, or a compile-time error occurs. 如果S不是参数化类型或原始类型,则T必须实现S ,并且静态地知道强制转换是正确的,否则会发生编译时错误。
      • Otherwise, S is either a parameterized type that is an invocation of some generic type declaration G , or a raw type corresponding to a generic type declaration G . 否则, S是参数化类型,它是某种泛型类型声明G的调用,或者是对应于泛型类型声明G的原始类型。 Then there must exist a supertype X of T , such that X is an invocation of G , or a compile-time error occurs. 然后必须存在T的超类型X ,这样XG的调用,或者发生编译时错误。 Furthermore, if S and X are provably distinct parameterized types then a compile-time error occurs. 此外,如果SX可证明是不同的参数化类型,则发生编译时错误。
  • If S is a type variable, then this algorithm is applied recursively, using the upper bound of S in place of S . 如果S是一个类型变量,则递归地应用该算法,使用S的上限代替S。
  • If S is an array type SC [], that is, an array of components of type SC : 如果S是数组类型SC [],即SC类型的组件数组:
    • If T is a class type, then if T is not Object , then a compile-time error occurs (because Object is the only class type to which arrays can be assigned). 如果T是类类型,那么如果T不是Object ,则会发生编译时错误(因为Object是可以为其分配数组的唯一类类型)。
    • If T is an interface type, then a compile-time error occurs unless T is the type java.io.Serializable or the type Cloneable , the only interfaces implemented by arrays. 如果T是接口类型,则发生编译时错误,除非Tjava.io.Serializable类型或Cloneable类型,这是由数组实现的唯一接口。
    • If T is a type variable, then: 如果T是一个类型变量,那么:
      • If the upper bound of T is Object or the type java.io.Serializable or the type Cloneable , or a type variable that S could legally be cast to by recursively applying these rules, then the cast is legal (though unchecked). 如果T的上限是Objectjava.io.Serializable类型或Cloneable类型,或者通过递归应用这些规则可以合法地转换为S的类型变量,则转换是合法的(虽然未选中)。
      • If the upper bound of T is an array type TC[] , then a compile-time error occurs unless the type SC[] can be cast to TC[] by a recursive application of these compile-time rules for casting. 如果T的上限是数组类型TC [] ,则发生编译时错误,除非通过递归应用这些编译时规则进行转换,可以将类型SC []强制转换为TC []
      • Otherwise, a compile-time error occurs. 否则,发生编译时错误。
    • If T is an array type TC [], that is, an array of components of type TC , then a compile-time error occurs unless one of the following is true: 如果T是数组类型TC [],即TC类型的组件数组,则会发生编译时错误,除非满足下列条件之一:

    • TC and SC are the same primitive type. TCSC是相同的原始类型。
    • TC and SC are reference types and type SC can be cast to TC by a recursive application of these compile-time rules for casting. TCSC是引用类型,类型SC可以通过递归应用这些编译时规则进行转换来转换为TC

Perfectly clear now, isn't it? 现在完全清楚,不是吗? :D :d

In other words, this is the best I can do without knowing more details about your problem. 换句话说,如果不了解有关您问题的更多详细信息,这是我能做的最好的事情。

A likely cause of class cast mystifcation is that not only do the types have to match but also they must be loaded by the same classloader. 类转换神秘化的一个可能原因是,不仅类型必须匹配,而且它们必须由相同的类加载器加载。

You should be able to dump not only the type hierarchy but also the identity of the classloader for each class. 您不仅可以转储类型层次结构,还可以转储每个类的类加载器的标识。

These kind of problems are not uncommon in appserver-style environments where application code and infratructure code are deliberately isolated - for example if system classes are accidentally included in applciation JARs you can have two copies of the "same" class inthe JVM and life gets confusing 这些问题在应用程序风格的环境中并不罕见,其中应用程序代码和基础结构代码是故意隔离的 - 例如,如果系统类意外地包含在applciation JAR中,您可以在JVM中拥有两个“相同”类的副本,并且生活变得混乱

其他有用且权威的参考资料可在Java虚拟机规范中找到,特别是§2.6.5,“缩小参考转换”,尤其是checkcast指令的定义。

Casting asserts that the runtime type of an object is compatible with the given static type, and thus allows you to call methods of that type on the object. Casting断言对象的运行时类型与给定的静态类型兼容,因此允许您在对象上调用该类型的方法。

Here obj is a Integer object, but only accessible though an Object reference: 这里obj是一个Integer对象,但只能通过Object引用访问:

Object obj = new Integer(1);

Casting lets you treat it as an Integer (or some superclass of Integer) again: Casting允许您再次将其视为Integer(或Integer的某个超类):

System.out.println(((Integer) obj).intValue());

ClassCastException occours when the static type given does not match the runtime type of the object: 当给定的静态类型与对象的运行时类型不匹配时,ClassCastException会出现:

System.out.println(((Float) obj).intValue()); // runtime error

You can find the runtime type of any object by using getClass() and the various Class methods: 您可以使用getClass()和各种Class方法找到任何对象的运行时类型:

System.out.println(obj.getClass()); // prints "class java.lang.Integer"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM