Java允许将byte分配给java.lang.Short,但不允许将其分配给java.lang.Integer。

9
final byte b = 12;  
Short s = b;  
Integer i = b;

这个程序用Short编译没有问题,但是使用Integer编译时会出现"不兼容的类型"错误信息。

我很难理解这种情况。我在这种特定情况下找不到任何相关内容。


使用 int 代替 Integer - Sanjay Dutt
在我看来,“非常相关”的问题没有充分的答案 - 只有一群人在进行猜测。我认为关闭这个问题是一个错误。 - Dawood ibn Kareem
4
情节变得更加扑朔迷离:移除“final”关键字会导致短整型自动装箱也产生编译错误。这可能是导致这种奇怪行为的一些线索。 - Kevin Workman
1
还有另一个奇怪的细节:Character c = b 也可以编译通过。但是 char 是无符号的!那么当你把 b 改成 -12 时会发生什么呢?它就无法编译了! - Mark Peters
这个问题有一个很好的答案:https://dev59.com/j18e5IYBdhLWcg3w2dYD#25294449 - Sanjay Dutt
显示剩余2条评论
1个回答

7

我尝试在更广泛的任务上下文中复制这个操作:

final byte b = 12;
Byte b2 = b;
Character c = b;  // Only an error if b isn't final
char c2 = b;      // Only an error if b isn't final
Short s = b;      // Only an error if b isn't final
short s2 = b;
Integer i = b;  // Error, as indicated in the question
int i2 = b;
Long l = b;     // Also an error
long l2 = b;
Float f = b;    // Also an error
float f2 = b;
Double d = b;   // Also an error
double d2 = b;

不仅赋值给Integer,而且赋值给FloatLongDouble也是错误的。 有趣的是,如果b的原始声明不是final,那么赋值给CharactercharShort也会失败。 JLS第5.2节对赋值上下文及其允许的转换有所启示。
分配上下文允许使用以下之一:
  • 身份转换 (§5.1.1)
  • 扩展原始类型转换 (§5.1.2)
  • 扩展引用类型转换 (§5.1.5)
  • 装箱转换 (§5.1.7),可选择紧随其后的扩展引用类型转换
  • 拆箱转换 (§5.1.8),可选择紧随其后的扩展原始类型转换。
这涵盖了所有转换为更宽泛的原始变量,无论b是否是final,都是允许的。(这仅适用于b不是负数的情况,在这种情况下,对无符号的char(或Character)进行赋值将失败。)接着说:
此外,如果表达式是byte、short、char或int类型的常量表达式(§15.28):
  • 如果变量的类型是byte、short或char,并且常量表达式的值可以表示为变量的类型,则可以使用缩小原始转换。

  • 如果变量的类型是Byte,并且常量表达式的值可以表示为byte类型,则可以使用缩小原始转换后跟装箱转换。

  • 如果变量的类型是Short,并且常量表达式的值可以表示为short类型,则可以使用缩小原始转换后跟装箱转换。

  • 如果变量的类型是Character,并且常量表达式的值可以表示为char类型,则可以使用缩小原始转换后跟装箱转换。

因为bfinal,表达式b是一个常量表达式,允许将其从int常量表达式12缩小到bytecharshort,然后装箱为ByteCharacterShort,但奇怪的是,不能转换为Integer或任何"以上"的类型。我能想到的唯一可能的解释是,受原始缩小转换影响的常量表达式不能被特别允许转换为IntegerLongFloatDouble
如果b不是final,那么缩小后再装箱是不允许的,非常量表达式也无法从byte升级到char

字符 c = b; // 只有在 b 不是 final(或 b 为负数)时才会出错。很棒的答案! - Mark Peters
@MarkPeters 确实。如上所述的JLS引用,“常量表达式的值可以表示为变量的类型”。负的final b也会导致char c = b;失败并出现错误。 - rgettman
但奇怪的是,没有转换为Integer或任何“更高级”的类型。我认为这是可以预料的,因为在那个时候,您正在使用ShortInteger,这些包装类型无法进行扩展。请参见$JLS 5.1.5从任何引用类型S到任何引用类型T都存在扩展引用转换,前提是ST的子类型。显然,ShortInteger之间没有直接联系。 - Jeroen Vannevel
1
@JeroenVannevel 是的,但我觉得奇怪的是,扩展原始转换后跟装箱转换并没有被特别允许。 - rgettman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接