可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm confused why Java integer literals default to int
instead of long
. This seems to cause unnecessary confusion.
First, it requires the programmer to adopt a special syntax (append "L" to literals) when assigning a value to a long
that exceeds the maximum int
size (2147483647).
long x = 2147483647; // Compiles
long y = 2147483648; // Does not compile
long z = 2147483648L; // Compiles
Second, when using the Long
wrapper class, the programmer must always use the long
literal notation as explained in this SO question.
Long x = 250; // Does not compile
Long y = 250L; // Compiles
Third, considering that implicit conversion from int
literals to the "narrower" data types (short
and byte
) works just fine in all situations (that I know of), it seems that simply making all integer literals type long
would have been the obvious solution... right? Wouldn't this completely remove the need for this odd system of appending "L" to integer literals in special cases?
回答1:
This behavior is by design1 and is codified in the JLS: Java Language Specification.
First, note that this is not related to widening which is why the (valid) integer-literal is promoted to a long value. Instead, this is related to the very specification of the int literal:
It is a compile-time error if a hexadecimal, octal, or binary int literal does not fit in 32 bits.
The smallest and largest signed 32-bit integer values are -2147483648 and 2147483647, respectively.
1I care not speculate on why it works this way, and languages like C# have different rules.
回答2:
Speed
You have efficiency gains by only using the size that you need. An int is fine for numbers from -2^31 to 2^31. If you use a long where an int would suffice, you slow down your code. For example, this code runs at 7.116 seconds on my machine. By switching it to using int, I decrease the running time to 3.74 seconds on my machine:
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 ");
}
}
Changed to use 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;
}
}
回答3:
One of the possible reasons that int
is default literal is that using lont
could cause hard to detect errors in multi-threading application as specified in JLS 17.7 Non-atomic Treatment of double and long.
For the purposes of the Java programming language memory model, a single write to a non-volatile long or double value is treated as two separate writes: one to each 32-bit half. This can result in a situation where a thread sees the first 32 bits of a 64-bit value from one write, and the second 32 bits from another write.
回答4:
I think you are right, long
would be a better default today. Back in 1995, long
was probably too long to be the default.
回答5:
For the
Long x = 250;
That won't work. Java uses Autoboxing, which casts automatically from the Object representative class to the primitive type. As for the other ones, int's are just the primary number type used. Longs, well at least for what I use them most often for, are used for dates and times only. Integers on the other hand are used by default for everything else.
If you really want to get into specifics, I'm sure this will rustle your jimmies more:
float pi = 3.14; // Does not compile.
float pi = 3.14F; // Compiles
In this case as well, double takes the priority when there is a decimal involved.
回答6:
I think the reason for making int literals the ones that don't need a type indication is that int is intended to be the normal integer type. Similarly, double is the normal floating point type. The idea seems to be to limit the number of literals that need a type indication by defaulting to the commonest type.
回答7:
It would be possible for a language to require that all integer arithmetic which would not overflow if intermediate results were computed with the longest integral type, as though they were. In such a language, if variables starting with L are 64 bits, those with W are 32-bits, and those with H are 16 bits, expressions like
L1 = W1*W2;
W3 = (W1+W2) >> 1
will be evaluated in such fashion as to avoid overflow, but an expression like
W4 = W1+W2
will be evaluated using 32-bit math (since any overflow that would occur then would occur with the assignment to W4 even if the intermediate result were evaluated as 32 bits), and an expression like
W5 = (H1*H2) >> 1
could be evaluated as 32 bits since the result couldn't overflow a 32-bit value.
Such a language could be quite efficient in most scenarios, since it would generally not hard for a compiler to determine the maximum relevant integer size for each subexpression. In such a language, it wouldn't matter whether a numeric literal was a "long" or an "int", since the compiler would be more interested in its numeric value.
In Java, however, numeric literals of different sizes have different semantics. If one multiplies an int
by the constant 128, the int
must be no larger than 16,777,215 or else an overflow will occur. If one multiplies the int
by a constant 128L
, the result may only be stored someplace that can accept a long
.