我很困惑为什么Java整数文本默认为int
而不是long
。这似乎造成了不必要的混乱。
首先,它要求程序员在为超过最大int
大小(2147483647)的long
赋值时采用特殊语法(在文字后附加"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
文本到"较窄"数据类型(short
和byte
)的隐式转换在所有情况下都很好(据我所知),简单地将所有整数文本设置为long
类型似乎是显而易见的解决方案。。。正确的这不是完全消除了在特殊情况下将"L"附加到整数字面值的奇怪系统的需要吗?
此行为是设计的1,并在JLS:Java语言规范中进行了编码。
首先,请注意,这与加宽无关,这就是为什么(有效)整数文字被提升为长值的原因。相反,这与int文本的规范有关:
如果十六进制、八进制或二进制int文字不适合32位,则是编译时错误。
最小和最大的带符号32位整数值分别为-2147483648和2147483647。
1我不想猜测为什么是这样工作的,而像C#这样的语言有不同的规则。
速度
您只需使用所需的尺寸即可提高效率。int适用于-2^31到2^31之间的数字。如果您使用一个长整型就足够了,那么您的代码就会变慢。例如,这段代码在我的机器上以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
是默认文字的一个可能原因是,使用long
可能会导致多线程应用程序中难以检测的错误,如JLS 17.7双和长的非原子处理中所述。
为了Java编程语言内存模型的目的,对非易失性长值或双值的一次写入被视为两次单独的写入:一次写入32位的一半。这可能导致线程从一次写入中看到64位值的前32位,从另一次写入看到第二个32位的情况。
我认为你是对的,long
将是今天更好的默认值。早在1995年,long
可能太长了,不能作为默认值。
对于
Long x = 250;
那行不通。Java使用Autoboxing,它自动从Object代表类转换为基元类型。至于其他类型,int只是使用的主要数字类型。Longs,至少是我最常使用的Longs,只用于日期和时间。另一方面,默认情况下,整数用于其他所有内容。
如果你真的想深入了解细节,我相信这会让你更加头疼:
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
必须不大于16777215,否则将发生溢出。如果将int
乘以常数128L
,则结果可能仅存储在可以接受long
的地方。