java 从 int 自动装箱到 java.lang.Long 转换问题
java autoboxing from int to java.lang.Long casting issue
我从平凡的减法中得到编译错误
Long result;
int operand1 = 10;
int operand2 = 5;
result = operand1 - operand2;
从最后一行开始:
incompatible types: int cannot be converted to java.lang.Long
除了我相信它可以转换之外,最好的解决方案是什么?以下任何一个都可以编译,但看起来很尴尬
result = (long) operand1 - operand2;
result = (long) (operand1 - operand2);
result = new Long (operand1 - operand2);
result = Long.valueOf(operand1 - operand2);
哪一个最适合性能?
前两行应该是性能最好的,因为您没有创建任何对象。 'long' 是原始数据类型,而 'Long' 是 long 的包装器 class。在前两个之间,我想说第二个要快一点,因为你对 int 进行减法,然后将单个值转换为 long,而在第一个中 - 你将两个值都转换为 long,然后对 long 进行减法这会有点慢。
关于编译问题 - 基本类型会自动转换为更大的类型,即如果减去它们,int 会转换为 long。但是,如果您将该 int 的值分配给 Long class 对象,则会出现编译错误,因为自动转换不会发生,因此您必须手动将 int primitive 转换为 long primitive 或 Long对象。
2和4基本一样。如果它们生成相同的字节码,我不会感到惊讶。
1 在性能方面与 2 和 4 几乎相同,但如果 2 和 4 中的整数减法溢出,它可能会产生略微不同的答案。
- 1 相当于
Long.valueOf((long) op1 - (long) op2)
- 2和4等同于
Long.valueOf((long) (op1 - op2))
我唯一要避免的是 3,因为这个 肯定会 产生一个新值,而其他 可能 使用缓存值, 取决于 Long.valueOf
:
的实现
[Long.valueOf
] returns a Long instance representing the specified long value. If a new Long instance is not required, this method should generally be used in preference to the constructor Long(long), as this method is likely to yield significantly better space and time performance by caching frequently requested values. Note that unlike the corresponding method in the Integer class, this method is not required to cache values within a particular range.
再看javac 1.8生成的字节码0_66:
(result
分配到槽1,operand1
分配到槽2,operand2
分配到槽3)
方法一:
result = (long) operand1 - operand2;
5: iload_2
6: i2l
7: iload_3
8: i2l
9: lsub
10: invokestatic #2 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
13: astore_1
方法二:
result = (long) (operand1 - operand2);
14: iload_2
15: iload_3
16: isub
17: i2l
18: invokestatic #2 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
21: astore_1
方法三:
result = new Long (operand1 - operand2);
22: new #3 // class java/lang/Long
25: dup
26: iload_2
27: iload_3
28: isub
29: i2l
30: invokespecial #4 // Method java/lang/Long."<init>":(J)V
33: astore_1
方法四:
result = Long.valueOf(operand1 - operand2);
这产生与方法 2 完全相同的字节码。为简洁起见省略。
如您所见,所有四种方法都构造了一个新的 Long
对象,因为 Long.valueOf()
将调用 new Long()
(尽管 Long.valueOf()
缓存 Long
值介于 -128 和 127 之间的对象(至少 Java 1.8.0_66)。如果值在在那个范围内,调用构造函数实际上要快一点,因为它绕过了缓存检查!)。
方法五:
如果您对速度感兴趣,请不要使用自动装箱,而要使用原始类型。这是变化:
long result; // not Long
并且原始语句在没有编译器投诉的情况下工作:
result = operand1 - operand2;
6: iload_3
7: iload 4
9: isub
10: i2l
11: lstore_1
如本页其他地方所述,可能存在溢出问题:首先减去整数,然后转换为长整数。最好对所有 3 种类型简单地使用 long
(这将跳过上面的 i2l
)。
我从平凡的减法中得到编译错误
Long result;
int operand1 = 10;
int operand2 = 5;
result = operand1 - operand2;
从最后一行开始:
incompatible types: int cannot be converted to java.lang.Long
除了我相信它可以转换之外,最好的解决方案是什么?以下任何一个都可以编译,但看起来很尴尬
result = (long) operand1 - operand2;
result = (long) (operand1 - operand2);
result = new Long (operand1 - operand2);
result = Long.valueOf(operand1 - operand2);
哪一个最适合性能?
前两行应该是性能最好的,因为您没有创建任何对象。 'long' 是原始数据类型,而 'Long' 是 long 的包装器 class。在前两个之间,我想说第二个要快一点,因为你对 int 进行减法,然后将单个值转换为 long,而在第一个中 - 你将两个值都转换为 long,然后对 long 进行减法这会有点慢。
关于编译问题 - 基本类型会自动转换为更大的类型,即如果减去它们,int 会转换为 long。但是,如果您将该 int 的值分配给 Long class 对象,则会出现编译错误,因为自动转换不会发生,因此您必须手动将 int primitive 转换为 long primitive 或 Long对象。
2和4基本一样。如果它们生成相同的字节码,我不会感到惊讶。
1 在性能方面与 2 和 4 几乎相同,但如果 2 和 4 中的整数减法溢出,它可能会产生略微不同的答案。
- 1 相当于
Long.valueOf((long) op1 - (long) op2)
- 2和4等同于
Long.valueOf((long) (op1 - op2))
我唯一要避免的是 3,因为这个 肯定会 产生一个新值,而其他 可能 使用缓存值, 取决于 Long.valueOf
:
[
Long.valueOf
] returns a Long instance representing the specified long value. If a new Long instance is not required, this method should generally be used in preference to the constructor Long(long), as this method is likely to yield significantly better space and time performance by caching frequently requested values. Note that unlike the corresponding method in the Integer class, this method is not required to cache values within a particular range.
再看javac 1.8生成的字节码0_66:
(result
分配到槽1,operand1
分配到槽2,operand2
分配到槽3)
方法一:
result = (long) operand1 - operand2;
5: iload_2
6: i2l
7: iload_3
8: i2l
9: lsub
10: invokestatic #2 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
13: astore_1
方法二:
result = (long) (operand1 - operand2);
14: iload_2
15: iload_3
16: isub
17: i2l
18: invokestatic #2 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
21: astore_1
方法三:
result = new Long (operand1 - operand2);
22: new #3 // class java/lang/Long
25: dup
26: iload_2
27: iload_3
28: isub
29: i2l
30: invokespecial #4 // Method java/lang/Long."<init>":(J)V
33: astore_1
方法四:
result = Long.valueOf(operand1 - operand2);
这产生与方法 2 完全相同的字节码。为简洁起见省略。
如您所见,所有四种方法都构造了一个新的 Long
对象,因为 Long.valueOf()
将调用 new Long()
(尽管 Long.valueOf()
缓存 Long
值介于 -128 和 127 之间的对象(至少 Java 1.8.0_66)。如果值在在那个范围内,调用构造函数实际上要快一点,因为它绕过了缓存检查!)。
方法五: 如果您对速度感兴趣,请不要使用自动装箱,而要使用原始类型。这是变化:
long result; // not Long
并且原始语句在没有编译器投诉的情况下工作:
result = operand1 - operand2;
6: iload_3
7: iload 4
9: isub
10: i2l
11: lstore_1
如本页其他地方所述,可能存在溢出问题:首先减去整数,然后转换为长整数。最好对所有 3 种类型简单地使用 long
(这将跳过上面的 i2l
)。