簡體   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