【问题标题】:Why initialization of new Long Wrapper with int literal is valid?为什么用 int 字面量初始化新的 Long Wrapper 是有效的?
【发布时间】:2017-07-23 08:19:20
【问题描述】:

查看Long的Java Doc,它只有两个构造函数:

    1) primitive long as param --> new Long(10L);  
    2) String as param --> new Long("23");

但这行得通 新长(23);

但如果字面量大于 int MAX VALUE (2147483647),则 L 后缀成为强制性的,因此:( new Long(2147483648) 现在需要在值后面加一个 L

但是: new Long(Integer.MAX_VALUE + 1) 没问题

谁能解释一下?

【问题讨论】:

标签: java initialization long-integer


【解决方案1】:

您问题的第一部分很简单:在需要long 的地方传递int 是允许的,因为任何可以表示为int 的数字也可以表示为long。这就是所谓的加宽转换

第二部分,关于new Long(Integer.MAX_VALUE + 1),比较棘手。尽管这里也发生了扩大转换,但它并不像人们想象的那样:如果你运行这个程序

Long x = new Long(Integer.MAX_VALUE + 1);
System.out.println(x);

你得到-2147483648,而不是预期的2147483648,因为int在加法时溢出(demo)。

编译器不够聪明,无法在执行加法之前将部分表达式提升为long。加法运算完成后发生加宽转换,加法运算结果溢出。

【讨论】:

    【解决方案2】:

    你可以在javadocs找到答案:

    在 strictfp 表达式(第 15.4 节)中,从整数类型到另一种整数类型或从 float 到 double 的扩展原语转换根本不会丢失任何信息;数值被完全保留。

    整数值23 可以转换为long 23L,而不会丢失任何信息。因此,通过加宽原始转换的使用,JVM 将其隐式转换为23L

    所以当你打电话时

    new Long(23)
    

    变成了

    new Long(23L)
    

    【讨论】:

      【解决方案3】:

      当我们写 new Long(23) 时,你可以把它想象成如下发生的事情:

      int i = 23;
      long l = i; // widening primitive conversion
      Long newLong = new Long(l);
      

      根据 JLS 5.1.2 允许扩大转换,因此没有问题。

      当我们尝试改用 new Long(2147483648) 时,第一步本身会失败,因为该值超出了 int 可以容纳的值

       int i = 2147483648;  // doesn't fit in int
      

      当我们尝试new Long(Integer.MAX_VALUE + 1) 时,您可以将其视为如下发生的事情:

       int i = Integer.MAX_VALUE + 1; // This gives the INTEGER.MIN_VALUE -2147483648
       long l = i ; // widening primitive conversion
       Long newLong = new Long(l);
      

      所以,这是允许的。希望这会有所帮助。

      【讨论】:

        【解决方案4】:

        区别在于是否使用文字。

        通过使用文字,

        long1 = new Long(2147483648)
        

        代码不会编译,因为编译器会再次检查文字的有效性,接收文字值的变量的类型和2147483648 超出了int 的范围。
        所以编译器发出一个错误。

        它适用于任何文字。
        作为compiler expects to have a specific type as value of the literals,它会进行检查:

        字面量的类型确定如下:

        以 L 或 l 结尾的整型文字(第 3.10.1 节)的类型是 long (§4.2.1)。

        任何其他整数文字的类型都是 int(第 4.2.1 节)。

        ...

        通过使用计算:

        long1 = new Long(Integer.MAX_VALUE + 1);
        

        编译器不会检查 Long 参数构造函数的大小是否在 int 范围内。
        这不是文字声明。
        在运行时,会发生 intlong 的扩展原语转换。

        它产生了一个intInteger.MAX_VALUE + 1,即-2147483648int 的溢出),它被转换为long 值。

        【讨论】:

          猜你喜欢
          • 2018-02-03
          • 2015-03-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-05-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多