为什么范围内缩小的长值不会被隐式转换?

时间:2014-09-08 04:38:23

标签: java compiler-construction constants literals

当我们声明static final时,Java编译器(或预编译器?)似乎足够聪明,可以检测到超出范围的数字:

public class Test {
    // setup variables:
    public static final int i_max_byte = 127;
    public static final int i_max_byte_add1 = 128;
    public static final int i_max_short = 32767;
    public static final int i_max_short_add1 = 32768;
    public static final int i_max_char = 65535;
    public static final int i_max_char_add1 = 65536;
    public static final char c_max_byte = 127;
    public static final char c_max_byte_add1 = 128;
    public static final char c_max_short = 32767;
    public static final char c_max_short_add1 = 32768;
    public static final short s_min_char = 0;
    public static final short s_min_char_sub1 = -1;
    public static final short s_max_byte = 127;
    public static final short s_max_byte_add1 = 128;

    // all these are OK:
    public static final byte b1 = i_max_byte;
    public static final byte b2 = s_max_byte;
    public static final byte b3 = c_max_byte;
    public static final byte b4 = (short) i_max_byte;
    public static final byte b5 = (char) i_max_byte;
    public static final char c1 = i_max_char;
    public static final char c2 = s_min_char;
    public static final short s1 = i_max_short;
    public static final short s2 = c_max_short;

    // pre-compiler complains "type-mismatch":
    public static final byte _b1 = i_max_byte_add1;
    public static final byte _b2 = s_max_byte_add1;
    public static final byte _b3 = c_max_byte_add1;
    public static final byte _b4 = (short) i_max_byte_add1;
    public static final byte _b5 = (char) i_max_byte_add1;
    public static final char _c1 = i_max_char_add1;
    public static final char _c2 = s_min_char_min_us1;
    public static final short _s1 = i_max_short_add1;
    public static final short _s2 = c_max_short_add1;
}

上面的代码证明,对于intshortchar值,编译器仅在值超出指定变量类型的范围时才会发出警告。

但是对于long值,即使数字在范围内,编译器也会抱怨:

public class Test2 {
    public static final long l_max_byte = 127;
    public static final long l_max_byte_add1 = 128;
    public static final long l_max_char = 32767;
    public static final long l_max_char_add1 = 32768;
    public static final long l_max_short = 65535;
    public static final long l_max_short_add1 = 65536;
    public static final long l_max_int = 2147483647;
    public static final long l_max_int_add1 = 2147483648L;

    // "type-mismatch" for all:
    public static final byte b1 = l_max_byte;
    public static final byte b2 = l_max_byte_add1;
    public static final char c1 = l_max_char;
    public static final char c2 = l_max_char_add1;
    public static final short s1 = l_max_short;
    public static final short s2 = l_max_short_add1;
    public static final int i1 = l_max_int;
    public static final int i2 = l_max_int_add1;
}

为什么编译器只对intshortchar值的范围检测很聪明?

为什么编译器不对long值进行范围检测?

1 个答案:

答案 0 :(得分:3)

答案可能不太令人满意,但......

Java Language Specification, Section 5.2,说:

  

赋值上下文允许将表达式的值赋值(第15.26节)给变量;必须将表达式的类型转换为变量的类型。

     

...

     

此外,如果表达式是byte,short,char或int类型的常量表达式(第15.28节):

     
      
  • 如果变量的类型是byte,short或char,则可以使用缩小的基元转换,并且常量表达式的值可以在变量的类型中表示。
  •   

对于编译正常的情况,常量表达式始终为shortcharint类型,并且该值可在目标类型中表示。对于long类型,根据规范,根本不允许这样的转换。


答案可能不太令人满意,因为下一个显而易见的问题是:

  

为什么他们这样编写规范?

这可以部分地通过JLS的链接部分中给出的示例来回答:这种隐式转换很可能主要用于您要编写声明的情况,如

byte b = 42;

因为否则,您必须将int值42转换为字节,如

byte b = (byte)42;

您希望从byte值初始化long的情况在这个意义上并不常见。