当前位置: 首页 > 知识库问答 >
问题:

为什么对象obj=新整数(2);字节b=(Byte)OBJ;运行时ClassCastException中的结果?

甘西岭
2023-03-14
Object obj = new Integer(2);
Byte b2 = (byte) obj; // at Runtime: ClassCastException "Integer cannot be cast to Byte"

我认为Integer(引用obj指向的)被解压缩为int,然后强制转换为byte,然后被压缩为byte并成功赋值。Eclipse编译器警告还说(稍微纠正一下):

  • 类型Object的表达式解压缩为字节
  • 类型byte的表达式被装箱为byte

那么为什么它不能将RHS中的这个字节分配到LHS中的字节引用中呢?

如果对象obj=新整数(2);,则long b2=(long)obj;工作,但long b2=7;失败。字节b2=(byte)obj;失败,但字节b2=7;没问题!也许在这些相互的差异中有一些线索?

从经验上看,我会说,在解装箱后禁止对基元类型进行缩窄(即使使用显式强制转换)(而允许扩大)--这可以解释这种行为。

终于明白了:

如果变量的类型为:

并且常数表达式的值可以在类型Byte中表示。

并且常量表达式的值可以用Short类型表示。

 Object o = new Integer(2);
 Integer i2 = (Integer) o; 
 Integer i3 = (int) o; 

共有1个答案

雍嘉勋
2023-03-14
Object obj = new Integer(2);
Byte b2 = (byte) obj;

装箱/取消装箱是静态地确定的,即在编译时。您已经强制转换为object,因此编译器不知道obj实际上是integer类型。相反,它生成的字节码假定为byte实例,以及一个显式检查(这是在运行时失败的检查):

ALOAD 1
CHECKCAST java/lang/Byte                                // Oh dear
INVOKEVIRTUAL java/lang/Byte.byteValue ()B              // Unbox as a Byte
INVOKESTATIC java/lang/Byte.valueOf (B)Ljava/lang/Byte; // Box as a Byte
ASTORE 2
Integer obj = new Integer(2);
Byte b2 = (byte) obj;

第二行甚至不编译。(byte)obj是一个强制转换上下文,有一系列规则定义这里允许的内容。1不允许先进行解装箱转换,然后进行缩小转换。

这些规则确实允许先进行解装箱转换,然后进行加宽转换,因此此代码编译并运行时不会出错:

Integer obj = new Integer(2);
Long b2 = (long) obj;
ALOAD 1
INVOKEVIRTUAL java/lang/Integer.intValue ()I            // Unbox as an Integer
I2L                                                     // Convert to long
INVOKESTATIC java/lang/Long.valueOf (J)Ljava/lang/Long; // Box as a Long
ASTORE 2
    null

那么,您别无选择,只能执行相关的强制转换链:

Object obj = new Integer(2);
Byte b2 = (byte)(int)(Integer) obj;

为了完整起见,下面是相应的字节码:

ALOAD 1
CHECKCAST java/lang/Integer                             // This is now ok
INVOKEVIRTUAL java/lang/Integer.intValue ()I            // Unbox as an Integer
I2B                                                     // Convert to byte
INVOKESTATIC java/lang/Byte.valueOf (B)Ljava/lang/Byte; // Box as a Byte
ASTORE 2

1。注意,由于=,这里还有一个赋值上下文,它有自己的一组规则。除其他外,不能执行长b2=7;,因为没有任何东西允许加宽转换后进行装箱转换。

 类似资料:
  • 描述 (Description) java.lang.reflect.Field.setByte(Object obj, byte value)方法将字段的值设置为指定对象上的字节。 声明 (Declaration) 以下是java.lang.reflect.Field.setBoolean(Object obj, byte value)方法的声明。 public void setByte(Obj

  • 本文向大家介绍请编写一个对象obj满足 obj=='a' && obj=='b' && obj=='c'相关面试题,主要包含被问及请编写一个对象obj满足 obj=='a' && obj=='b' && obj=='c'时的应答技巧和注意事项,需要的朋友参考一下

  • 描述 (Description) java.lang.reflect.Field.getByte(Object obj)方法获取静态或实例字节字段的值。 声明 (Declaration) 以下是java.lang.reflect.Field.getByte(Object obj)方法的声明。 public byte getByte(Object obj) throws IllegalArgu

  • 问题内容: 我的老板说我应该使用,因为它比更好,但是他不记得为什么这样做。有什么理由要使用吗? 我以某种方式感觉到…相反! 在Google上进行搜索后,我发现的唯一结果是: 在C语言中,它可以防止您意外地在条件结构中键入(obj = null)。 问题答案: 您不能通过输入来意外分配给它。但是,这是C时代的回忆,在Java中是不可能的,因为表达式返回赋值的右侧。由于不是,编译器会抱怨。 我会尽力向

  • 问题内容: 我试图了解何时以及如何在Python中正确使用super()(2.7.x或3.x) 在翻译告诉我怎么称呼它: 我了解在Python3.x中现在可以在类定义中使用super(),但是我不明白为什么不可能。或在类定义中。 我知道一定有原因,但是我找不到。对我来说,这些行等于或,并且行得通吗? 我认为即使在Python 3.x中,键入也是一个不错的快捷方式。 问题答案: 仅在Python 2

  • 对于那些不知道_. allKeys(obj)做什么的人,这里有一个片段 因此,它返回传递给它的对象的属性/方法名称数组。 这应该给我: 属性名称:firstname 值名称:John ------ 属性名称:lastname 值名称:Adams ------ 相反,它给了我: 属性名称:firstname 值名称:un定义 ------ 属性名称:lastname 值名称:un定义 ------