繁体   English   中英

从int到java.lang.Long的Java自动装箱问题

[英]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的包装类。 在前两个之间,我想说第二个要快一点,因为对int进行减法,然后将单个值转换为long,而在第一个中,将两个值都转换为long,然后对longs进行减法这会有点慢。

关于编译问题-基本类型会自动转换为更大的类型,即如果减去它们,int会转换为long。 但是,如果将那个int的值分配给Long类对象,则会得到编译错误,因为不会发生自动转换,因此,您必须手动将int原语转换为Long原语或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 ]返回一个Long实例,它表示指定的long值。 如果不需要新的Long实例,则通常应优先于构造方法 Long(long)使用此方法,因为此方法通过缓存经常请求的值可能会产生明显更好的空间和时间性能。 请注意,与Integer类中的相应方法不同, 不需要此方法来缓存特定范围内的值

让我们看一下javac 1.8.0_66生成的字节码:

result被分配给时隙1, operand1是在时隙2,和operand2在插槽3)

方法1:

结果=(长)操作数1-操作数2;

    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

方法二:

结果=(长)(操作数1-操作数2);

   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

方法3:

结果=新的Long(操作数1-操作数2);

   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

方法4:

结果= Long.valueOf(operand1-操作数2);

这产生与方法2完全相同的字节码。为简洁起见,省略了它。


如您所见,这四种方法都构造了一个新的Long对象,因为Long.valueOf()将调用new Long() (尽管Long.valueOf()缓存Long对象的值介于-128和127之间(至少在Java 1.8中如此)。 0_66)。如果值超出该范围,则调用构造函数实际上要快一点,因为它绕过了缓存检查!

方法5:如果您对速度感兴趣,请不要使用自动装箱,而应使用原始类型。 这是更改:

结果长 // 不久

并且原始语句在没有编译器投诉的情况下有效:

结果=操作数1-操作数2;

   6: iload_3
   7: iload         4
   9: isub
  10: i2l
  11: lstore_1

如本页其他地方所述,可能存在溢出问题:首先将int减去,然后将其转换为long。 最好对所有3种类型都使用long类型(这将跳过上面的i2l )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM