java - Long Literals in Java
问题描述
So reading through the documentation, it states that if you declare an int literal with an L on the end, it will read it as a long instead. Here is my question: is there any difference between this and just naming the type as a long to start with? For example:
int x = 100L;
VS.
long x = 100;
The same thing?
解决方案
tl;dr
is there any difference …
int x = 100L;
versuslong x = 100;
Yes. There is a major difference.
- The first will not compile, and will not run. You cannot cram a 64-bit
long
into a 32-bitint
. - The second is the opposite of the first, a widening of a 32-bit
int
primitive integer literal while being assigned to a 64-bitlong
primitive integer variable.
Details
There is much misinformation in the other Answers.
32-bit vs 64-bit integer primitives
The L
seen above means “<a href="https://en.wikipedia.org/wiki/64-bit_computing" rel="nofollow noreferrer">64-bit int
integer primitive” whereas the absence of a L
in an integer literal means “<a href="https://en.wikipedia.org/wiki/32-bit" rel="nofollow noreferrer">32-bit int
integer primitive”.
The following line fails to compile. You are attempting to place a 64-bit long
primitive literal into a 32-bit int
variable. Square peg, round hole. One of the compiler’s jobs is to stop such nonsense.
int x = 100L ; // BAD — compiler fails — Cannot place a 64-bit `long` `int` primitive in a 32-bit `int` variable.
Error … incompatible types: possible lossy conversion from long to int
Let’s correct that line by dropping the L
, assigning a 32-bit int
literal to a 32-bit int
variable.
int x = 100 ; // 32-bit `int` integer primitive literal being stored in a 32-bit `int` integer variable. No problem, no issues.
Primitives, not objects
Notice that, contrary to some other Answers seen on this page, the code above has no objects, only primitives.
Widening from 32-bit to 64-bit
In the next line, you are first creating a 32-bit int
primitive with the “100” part. That 32-bit int
primitive is then assigned to a 64-bit long
primitive. Java fills in the extra thirty-two bits with zeros, so effectively you end up with the same number.
long x = 100 ; // 32-bit `int` integer primitive being stored in a 64-bit `long` integer primitive. The extra 32-bits are filled in with zeros automatically by Java.
As noted in a comment by Andreas, this conversion from 32-bit to 64-bit integers is technically called widening. See JLS 5.1.2 Widening Primitive Conversion for a technical discussion.
Some people, including me, consider such code using literals that depend on automatic widening to be poor form. Your intentions as a programmer are ambiguous. So I would write that code using the appended L
, like this long x = 100L ;
. But some folks would consider this position to be needlessly worried about an inconsequential matter.
Casting
Contrary to some other Answers, there is no casting involved in the code seen above.
Here is an example of casting. We start with a 64-bit long
primitive. When then cast to an int
primitive, lopping off the higher 32-bits. The (int)
tells the compiler “yes, I know I am risking data loss in chopping off 32 of my 64 bits, but go ahead and do it, I am taking responsibility for this act”.
int x = (int) 100L ; // Start with a 64-bit `long` primitive literal, lop off 32 of the 64 bits, resulting in a 32-bit `int` primitive being assigned to a 32-bit primitive variable.
In this particular example, there is no problem, as a value of one hundred fits with the lower 32-bits, so the set of higher thirty-two bits being excised are all zeros. So no damage in this case. But also in this case, this code is senseless, and should not be done in real work. Indeed, in real work you would only rarely, if ever, have a productive reason to lop off half of a 64-bit integer’s bits by casting.
Narrowing with Math.toIntExact
A better alternative to casting is to call Math.toIntExact
. You pass a long
primitive to this method, and it returns an int
, the result of narrowing the 64-bit integer to 32-bit integer. The advantage over casting is that an ArithmeticException
is thrown if overflow occurs. So you will be informed of any data loss.
try {
int x = java.lang.Math.toIntExact( 100L ) ;
} catch ( ArithmeticException e ) {
… // Handle data loss, the overflow in going from 64-bits to 32-bits.
}
Objects
Because some other Answers incorrectly raised the subject of objects and auto-boxing, I'll mention a bit about that.
The wording Long
with an uppercase L
in the front means the Long
class rather than the long
primitive. I'll not explain the distinction here, except to say I wish Java had never made explicit use of primitives and had instead stuck to only classes. Indeed, there is a remote possibility that a version of Java in the far future may do exactly that (hide the existence of primitives).
But here and now, there is a distinction between classes/objects and primitives. To help smooth over that distinction, Java supports auto-boxing. As a convenience, in most scenarios the Java compiler and runtime can detect when your code is assigning a primitive to where an object is expected, and vice-versa.
Long myLongObject = 100L ; // This works because Java automatically detects the primitive `long` being assigned to an object of class `Long`, and instantiates a `Long` object to hold that number value.
That line above effectively is treated as if it is:
Long myLongObject = Long.valueOf( 100L ) ;
And is would be logically equivalent to the following, but technically this next line fails (compiler error) because there is no need for the L
in the string as the string is assumed to contain digits of a 64-bit integer. In other words, this input string is not an integer literal, so the L
is superfluous and not allowed.
Long myLongObject = Long.valueOf( "100L" ) ; // Compiler error. The `L` is not allowed because it is redundant.
Just drop the L
from that String input, as the input is assumed to represent a 64-bit number.
Long myLongObject = Long.valueOf( "100" ) ;
Java will also automatically widen from a 32-bit int
before also doing the autoboxing. So, the lines above are also effectively the same as this.
Long myLongObject = Long.valueOf( 100 ) ; // 32-bit `int` primitive literal automatically widened to a 64-bit `long`, then passed as argument to the `valueOf` method that takes only a `long`.
Again, the code seen in the Question has no involvement with classes/objects. This section of this Answer would be irrelevant except that other incorrect Answers raised the issues of objects & auto-boxing.
推荐阅读
- android - 安卓。触摸侦听器在两个视图之间混合
- javascript - 针对浏览器窗口大小?
- laravel-passport - Laravel 个人访问令牌过期
- javascript - 是否可以使用用户定义的 JS 变量字符串来输入 Flask 变量?
- reactjs - 如果我们使用 Typescript,我们如何使用 CDN URL 机制进行包管理?
- javascript - 如何安装 npm peerDependencies 以删除警告
- nginx - Nginx 批量 URL 重定向
- webgl - 通过生成 MipMap 对 Webgl2 R32F 纹理中的值求和
- javascript - json.stringify(obj) 错误 obj 未定义
- php - Wordpress 帖子丢失但在数据库中仍然可见