【问题标题】:why long COOKIE_TIMEOUT = 1000 * 60 * 60 * 24 * 30 return negative? [duplicate]为什么 long COOKIE_TIMEOUT = 1000 * 60 * 60 * 24 * 30 返回负数? [复制]
【发布时间】:2014-07-31 07:31:49
【问题描述】:
final long COOKIE_TIMEOUT = 1000 * 60 * 60 * 24 * 30;

输出:-1702967296

有人告诉我把 L 放在 1000 之后就可以了

final long COOKIE_TIMEOUT = 1000L * 60 * 60 * 24 * 30;

输出:2592000000

为什么会这样?

【问题讨论】:

  • 可能是整数溢出...??
  • 我在 eClipse 中测试过,结果为阴性?

标签: java long-integer


【解决方案1】:

整数溢出,放1000L,这样会强制长转换

更新 稍微长一点的解释:

例如,如果您只执行 1000*10,java 会将它们视为整数。 在您的原始代码中,您正在执行一个溢出的整数计算,然后将溢出的值转换为 long。

但是,如果您将 L 放在第一个数字之后,java 会将它们视为 long(最左边的操作数定义了粒度)并且您不会出现溢出。

再举一个例子:

double a = 5 / 2;
double b = 5d / 2;

System.out.println(a + " != " + b);

这将打印出来:

2.0 != 2.5

为什么?在计算 a 时,java 将 5 和 2 视为整数并进行整数除法,然后将结果转换为双精度数。在计算 b 时,你告诉 java 5 实际上是一个双精度数,此时它执行双除法。

【讨论】:

    【解决方案2】:

    虽然COOKIE_TIMEOUTlong,但右边的表达式由整数组成,所以它的类型是int。结果大于导致溢出的Integer.MAX_VALUE。当您的表达式中至少有一个操作数属于更高类型(例如long)时,整个表达式变为long,并且不会发生溢出。

    这是您在第二个示例中所做的,您在其中一个数字常量之后添加了L 修饰符。这个常量变成了long,所以表达式也变成了long

    【讨论】:

      【解决方案3】:

      这种行为是由于Java 编译器选择的表达式的类型。在这种情况下,它看起来像这样:

      int  * int  -> int (which overflows here during the multiplication)
      long * long -> long
      long * int  = long * long (by promotion) -> long
      int  * long = long (by promotion) * long -> long
      

      这种提升对于数学运算符来说几乎是普遍的:使用最宽/最大的类型,提升较小的类型并应用 x op x -> x 表达式(传统上是整数与浮点除法)。

      L 产生一个 long 值,因此选择的乘法是 long * long (by promotion) -> long,它不会立即发现溢出。 long 表达式结果类型传播到所有其他乘法。

      加分:如果写成1000 * 60 * 60 * 24 * 30 * 1L,它仍然会失败(溢出),为什么?

      【讨论】:

        【解决方案4】:

        它大于Integer.MAX_VALUE 2147483647

        默认情况下,所有数字文字都被视为Integer。要定义 Long 数值,您必须在数字中添加 L 或 'l'。

        【讨论】:

        • +1,Integer.MAX_VALUE 是 2147483647。
        • 我之前读过Long.MAX_VALUE后很害怕:p ;)
        • 呵呵... dat 甚至让我感到惊讶,更正...谢谢 sp00m 和 KisHan
        【解决方案5】:

        这种行为的原因是integer overflow

        你的第一句话可以这样理解:

        long time = 1000 * 60 * 60 * 24 * 30;

        一样
        int time = 1000 * 60 * 60 * 24 * 30;
        long timel = time;
        

        首先计算表达式,然后赋值给 long 类型;


        当你把后缀L 定义为文字时,你将它定义为长类型。

        JSL 3.10.1. Integer Literals

        如果整数文字以 ASCII 为后缀,则它的类型为 long 字母 L 或 l(ell);否则它是 int 类型(§4.2.1)。

        long time = 1000L * ( 60 * 60 * 24 * 30);

        也可以写成

        long time = ((long) 1000) * ( 60 * 60 * 24 * 30);

        更多关于Primitive Data Types

        【讨论】:

          【解决方案6】:
          It is causing for Integer overflow(Max value upto 2147483647). 
          

          您可以在任何数值的末尾添加 L

          点赞1000L

          然后强制转换为 Long 类型

          【讨论】:

            【解决方案7】:

            这里发生的情况是在分配到左侧之前评估右侧。由于您将多个ints 相乘,因此结果类型将为int。然后,在评估右侧之后,它会看到它应该将此值分配给 long,并自动进行转换。

            所以你有:

            评估右侧为int:1000 * 60 * 60 * 24 * 30 = 2,592,000,000

            int 的最大值为:2,147,483,647

            所以你有一个溢出,这使得 int 为负数。然后将其分配给一个长的,仍然是负数。

            当您将右侧的操作数之一指定为long 时,表达式将被评估为具有更大的最大值的long

            【讨论】:

              【解决方案8】:

              公式中的每个数字都是一个整数,因此 Java 将在 Integer 中执行所有计算并将结果临时存储为 Integer。但是结果超出了 Integer Max 范围(溢出),所以它变成了负数。

              1000 * 60 * 60 * 24 * 30 = 2592000000(超过 Integer.MAX_VALUE)

              只有当 Java 需要将其分配给 Long 变量时,Java 才会将其转换为 Long。由于结果已经是错误的结果(由于溢出),那么 Long 变量将被分配错误的结果。

              但是,如果您已经将 1000 声明为 Long (1000L),那么剩余的计算将作为 Long 而不是 Integer 进行。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2011-10-05
                • 2011-02-09
                • 2021-03-30
                • 1970-01-01
                • 2016-07-17
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多