从Java原语转换为包装类
在将基元分配给包装类引用时,我对Java编译器的行为感到困惑。 请参阅下面的代码。 带注释的行不会编译。
我不明白为什么的逻辑:
- 一个
byte
可以分配给Byte
或Short
,但不能分配给Integer
或Long
引用 -
short
可以分配给Byte
或Short
,但不能分配给Integer
或Long
引用 -
int
可以分配给Byte
,Short
或Integer
,但不能分配给Long
引用 -
long
可以分配给Long
,但不能分配给Byte
,Short
或Integer
我看不到这种模式。 对此的任何见解都将非常有用。 谢谢。
Byte s5 = (byte)7; Short s6 = (byte)7; Integer s7 = (byte)7; // Does not compile Long s8 = (byte)7; // Does not compile Byte s9 = (short)7; Short s10 = (short)7; Integer s11 = (short)7; // Does not compile Long s12 = (short)7; // Does not compile Byte s1 = (int)7; Short s2 = (int)7; Integer s3 = (int)7; Long s4 = (int)7; // Does not compile Byte s13 = (long)7; // Does not compile Short s14 = (long)7; // Does not compile Integer s15 = (long)7; // Does not compile Long s16 = (long)7;
我们来看一下赋值上下文中允许的转换类型。
原则上:
赋值上下文允许使用以下之一:
身份转换
扩大原始转换
扩大参考转换
一个拳击转换,可选地后跟一个加宽的引用转换
取消装箱转换,可选地后跟扩展的原始转换。
(注意我强调一个 。)
例如,大多数不编译的示例
Integer s11 = (short)7;
需要扩展原始转换,然后进行装箱转换 。 这不是允许的转换。
但是你可能想知道为什么下面的例子会编译:
Byte s9 = (short)7;
这是一个缩小的原始转换,然后是拳击转换 。
这是一个特例:
另外,如果表达式是
byte
,short
,char
或int
类型的常量表达式,如果变量的类型是:则可以使用缩小的原语转换,然后使用装箱转换:
Byte
和常量表达式的值可在类型byte
表示。
Short
和常量表达式的值可以在short
类型中表示。
Character
和常量表达式的值可在char
类型中表示。
这种特殊情况是必要的,因为无法表达比int
更窄的类型的整数文字。
这似乎是特定于编译器的行为。 当我将代码粘贴到Eclipse中,运行Java 7时,我没有看到您向Integer
报告的编译器错误或者向Integer
报告的byte
。
相反,我看到byte
, short
和int
都可以分配给Byte
, Short
和Integer
,但不能分配给Long
,而long
只能分配给Long
。 有趣的是,如果将变量更改为基元而不是包装类型,则byte
, short
和int
行为不会更改,但现在其他类型的赋值也可以long
。
javac 1.7.0_02 | byte | Byte || short | Short || int | Integer || long | Long | From byte | Yes | Yes || Yes | Yes || Yes | No || Yes | No | From short | Yes | Yes || Yes | Yes || Yes | No || Yes | No | From int | Yes | Yes || Yes | Yes || Yes | Yes || Yes | No | From long | No | No || No | No || No | No || Yes | Yes | Eclipse Indigo | byte | Byte || short | Short || int | Integer || long | Long | From byte | Yes | Yes || Yes | Yes || Yes | Yes || Yes | No | From short | Yes | Yes || Yes | Yes || Yes | Yes || Yes | No | From int | Yes | Yes || Yes | Yes || Yes | Yes || Yes | No | From long | No | No || No | No || No | No || Yes | Yes |
鉴于不同的编译器允许不同的转换,我怀疑在JLS中实际上没有拼写出“正确”的行为。 似乎某些转换是在封面下完成的,因为编译器编写者认为它很方便(例如, byte a = (int)1
是允许的但byte a = (int)1000
不是),不是因为它是语言的文档部分。
根据我的研究,我发现一个字节是一个8位有符号整数。 短裤是16位有符号整数。 因此我可以看出为什么它们是兼容的,它们都是两个补码的有符号整数,强调签名 。 long是64位整数,但它也可以是无符号的(考虑到它有比较无符号long的方法)。 这可能解释了为什么你的转换为long导致错误 – 你将一个带符号的字节转换为一个可能无符号的长整数。 (来源:阅读http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html上的原语)