java自动装箱从int到java.lang.Long转换问题

时间:2017-10-26 21:26:54

标签: java autoboxing

我从琐碎的减法中得到编译错误

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);

哪一个最适合表现?

3 个答案:

答案 0 :(得分:1)

由于您没有创建任何对象,因此前两行应该是性能最佳的。 'long'是原始数据类型,而'Long'是长期的包装类。在前两个之间,我会说第二个有点快,因为你在整数上减去然后将一个值转换为long,而在第一个 - 你将两个值转换为long然后再减去longs这会慢一些。

关于编译问题 - 原始类型会自动转换为更大的类型,即如果减去它们,int将转换为long。但是,如果将该int的值赋给Long类对象,则会出现编译错误,因为不会发生自动转换,因此您必须手动将int原语转换为long原语或Long对象。

答案 1 :(得分:1)

2和4基本相同。如果他们生成相同的字节码,我不会感到惊讶。

1与2和4在性能方面几乎相同,但如果2和4中的整数减法溢出,它可能会产生稍微不同的答案。

  • 1相当于Long.valueOf((long) op1 - (long) op2)
  • 2和4相当于Long.valueOf((long) (op1 - op2))

我唯一要避免的是3,因为肯定会产生一个新值,而其他可能使用缓存值,具体取决于{{3的实现}}:

  

[Long.valueOf]返回表示指定long值的Long实例。如果不需要新的Long实例,此方法通常应优先于构造函数 Long(long)使用,因为此方法可能通过缓存频繁请求的值来显着提高空间和时间性能。请注意,与Integer类中的相应方法不同,不需要此方法来缓存特定范围内的值

答案 2 :(得分:1)

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

result分配给广告位1,operand1位于广告位2中,operand2位于广告位3中)

方法1:

  

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

方法2:

  

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

方法3:

  

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

方法4:

  

result = Long.valueOf(operand1 - operand2);

这产生与方法2完全相同的字节码。为简洁而省略。

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

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

  结果很长; //不长

并且原始声明在没有编译器投诉的情况下工作:

  

result = operand1 - operand2;

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

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