为什么Java整数文字的默认类型是int而不是long?

我很困惑为什么Java整数文字默认为int而不是long 。 这似乎造成了不必要的混淆。

首先,它要求程序员在为超出最大int大小的int (2147483647)赋值时采用特殊语法(将“L”附加到文字)。

 long x = 2147483647; // Compiles long y = 2147483648; // Does not compile long z = 2147483648L; // Compiles 

其次,当使用Long包装类时,程序员必须始终使用long文字表示法,如本SO问题中所述 。

 Long x = 250; // Does not compile Long y = 250L; // Compiles 

第三,考虑到从int文字到“较窄”数据类型( shortbyte )的隐式转换在所有情况下(我知道)都可以正常工作,似乎简单地将所有整数文字类型设置为long将是明显的解决方案… 对? 难道这不会完全消除在特殊情况下对整数文字附加“L”的奇怪系统的需要吗?

此行为是设计1,并在JLS:Java语言规范中编纂。

首先,请注意,这与扩展无关,这就是将(有效)整数文字提升为long值的原因。 相反,这与int literal的规范有关:

如果hex,八进制或二进制int文字不适合32位,则为编译时错误。

最小和最大的带符号32位整数值分别为-2147483648和2147483647。


1我不关心为什么它以这种方式工作,而像C#这样的语言有不同的规则。

速度

只使用您需要的尺寸,您就可以提高效率。 对于从-2 ^ 31到2 ^ 31的数字,int是正常的。 如果你使用int就足够了,那么你的代码就会变慢。 例如,此代码在我的机器上运行7.116秒。 通过将其切换为使用int,我将机器上的运行时间减少到3.74秒:

 public class Problem005 { private static boolean isDivisibleByAll(long n, long ceiling) { for (long i = 1; i < ceiling; i++) if (n % i != 0) return false; return true; } public static long findSmallestMultiple (long ceiling) { long number = 1; while (!isDivisibleByAll(number, ceiling)) number++; return number; } } public class Stopwatch { private final long start; public Stopwatch() { start = System.currentTimeMillis(); } public double elapsedTime() { long now = System.currentTimeMillis(); return (now - start) / 1000.0; } } public class Main { public static void main(String[] args) { Stopwatch stopwatch005 = new Stopwatch(); long highestMultiple = 20; long findSmallestMultipleOutput = findSmallestMultiple(highestMultiple); double findSmallestMultipleTime = stopwatch005.elapsedTime(); System.out.println("Problem #005"); System.out.println("============"); System.out.print("The multiple of the numbers 1-" + highestMultiple + " is = "); System.out.print(findSmallestMultipleOutput); System.out.println(" with a time of " + findSmallestMultipleTime + " seconds.\n "); } } 

更改为使用int:

 public class Problem005 { private static boolean isDivisibleByAll(int n, int ceiling) { for (int i = 1; i < ceiling; i++) if (n % i != 0) return false; return true; } public static int findSmallestMultiple (int ceiling) { int number = 1; while (!isDivisibleByAll(number, ceiling)) number++; return number; } } 

int是默认文字的一个可能原因是使用lont可能导致难以检测multithreading应用程序中的错误,如JLS 17.7非primefaces性处理double和long中所规定的那样 。

出于Java编程语言存储器模型的目的,对非易失性 long或double值的单次写入被视为两个单独的写入:每个32位一半写入一次。 这可能导致线程从一次写入看到64位值的前32位,而从另一次写入看到第二次32位的情况。

我认为你是对的,今天long会更好。 早在1995年, long可能太长,不能成为默认值。

为了

 Long x = 250; 

那不行。 Java使用Autoboxing,它自动从Object代表类转换为基本类型。 至于其他的,int只是使用的主要数字类型。 多头,至少对于我最常使用它们而言,仅用于日期和时间。 另一方面,整数用于其他所有内容。

如果你真的想深入了解具体细节,我相信这会让你的jimmies更加生气勃勃:

 float pi = 3.14; // Does not compile. float pi = 3.14F; // Compiles 

在这种情况下,当涉及小数时,double取优先级。

我认为使int文字成为不需要类型指示的原因是int意图是普通的整数类型。 同样,double是正常的浮点类型。 这个想法似乎是通过默认为最常见的类型来限制需要类型指示的文字数量。

如果中间结果是用最长整数类型计算的,那么语言可能要求所有整数运算不会溢出,就好像它们一样。 在这种语言中,如果以L开头的变量是64位,那些带有W的变量是32位,那些带有H的变量是16位,表达式如下

 L1 = W1*W2; W3 = (W1+W2) >> 1 

将以避免溢出的方式进行评估,但表达方式如此

 W4 = W1+W2 

将使用32位数学进行评估(因为即使中间结果被评估为32位,随着W4的赋值也会发生任何溢出),以及类似的表达式

 W5 = (H1*H2) >> 1 

由于结果不能溢出32位值,因此可以将其评估为32位。

在大多数情况下,这样的语言可能非常有效,因为编译器通常不难确定每个子表达式的最大相关整数大小。 在这种语言中,数字文字是“long”还是“int”并不重要,因为编译器会对其数值更感兴趣。

但是,在Java中,不同大小的数字文字具有不同的语义。 如果将int乘以常量128,则int必须不大于16,777,215,否则将发生溢出。 如果将int乘以常量128L ,则结果可能只存储在可以接受long