簡體   English   中英

autoboxing是否調用valueOf()?

[英]Does autoboxing call valueOf()?

我正在嘗試確定以下語句是否保證是真的:

((Boolean)true) == Boolean.TRUE
((Boolean)true) == Boolean.valueOf(true)
((Integer)1) == Integer.valueOf(1)

我一直認為autoboxing相當於在相應的類型上調用valueOf() 我在這個主題上看到的每一個討論似乎都支持我的假設。 但我在JLS中找到的只有以下內容( §5.1.7 ):

如果值p被裝箱是文本類型的整數int之間-128127包容(§3.10.1)或布爾值truefalse (§3.10.3),或一個之間文字字符'\''\'包含(§3.10.4),然后讓ab成為p的任意兩次拳擊轉換的結果。 a == b總是如此。

這描述了 valueOf()相似的行為*。 但似乎沒有任何保證valueOf()實際上被調用,這意味着理論上可以有一個實現為自動裝箱值保留一個單獨的專用緩存。 在這種情況下,緩存的自動裝箱值與常規緩存的裝箱值之間可能不存在標識相同性。

Oracle的自動裝箱教程事實上說明了li.add(i)被編譯為li.add(Integer.valueOf(i)) ,其中i是一個int 但我不知道該教程是否應被視為權威來源。


*它比valueOf()稍微弱一些,因為它只引用文字值。

我首先提出你的問題是編譯器為自動裝箱生成了什么代碼?

但是,在您對@ElliottFrisch發表評論后,我發現它有所不同:

我知道編譯器的行為方式。 我想弄清楚這種行為是否得到保證。

對於其他讀者,假設“行為方式”意味着使用valueOf

請記住,Java有多個編譯器。 為了“合法”,他們必須遵守JLS中給出的合同。 因此,只要遵守此處的所有規則,就無法保證內部如何實施自動裝箱。

但我沒有看到任何理由不使用valueOf ,特別是它使用緩存值,並且是Joseph D. Darcy在本文中推薦的方法。

在語言規范提到它之前,不能保證自動裝箱等同於對靜態valueOf方法的調用。 它是一個實現方面,不是裝箱轉換規范的一部分。 理論上,只要符合您在JLS中提到的規則,實現就可以自由使用其他機制。

在實踐中,有許多Sun JDK錯誤報告(例如JDK-4990346JDK-6628737 )明確暗示當在Java 5中引入自動裝箱時,目的是讓編譯器依賴於JDK-6628737中所述的valueOf

JDK 5中為javac引入了靜態工廠方法Integer.valueOf(int),Long.valueOf(long)等,以實現自動裝箱規范所需的緩存行為。

但這只適用於javac,不一定是所有編譯器。

自動裝箱絕對執行valueOf() ...在OpenJDK的。 如果這是您的實施,請繼續閱讀......如果沒有,請跳至下方。

((Boolean)true) == Boolean.TRUE
((Boolean)true) == Boolean.valueOf(true)

Java文檔聲明Boolean.valueOf()始終返回Boolean.TRUEBoolean.FALSE ,因此在這些情況下您的引用比較將成功。

((Integer)1) == Integer.valueOf(1)

對於這個特定的例子,在具有默認設置的OpenJDK實現下,它可能會因為您選擇了一個在啟動時緩存的值<128這一事實而工作(雖然這可以作為命令行arg重寫)。 它也用於較大的值工作,如果是經常使用的,足以被緩存。 除非您在關於Integer緩存的“安全”假設下工作,否則不要期望引用比較是相等的。

LongShortCharacterByte偶然實現了這個緩存,但與Integer不同,它不可調。 如果你比較autobox / valueOf()引用, Byte將始終有效,因為很明顯,你不能超出范圍。 FloatDouble毫不奇怪總是會創建一個新實例。


現在,用純粹的通用術語? 請參閱JLS的這一部分 - 您必須在-128到127范圍內為boolean和任何intchar提供相同的引用。 其他任何事情都無法保證

Oracle的自動裝箱教程事實上說明了li.add(i)被編譯為li.add(Integer.valueOf(i)),其中i是一個int。 但我不知道該教程是否應被視為權威來源。

我正在運行Oracle Java 1.7.0_72,看起來它確實使用了valueOf。 下面是一些代碼和它的字節碼。 字節碼顯示它正在使用valueOf。

public class AutoBoxing {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Integer x = 5;
        int i = x;
        System.out.println(x.toString());
    }

}





Compiled from "AutoBoxing.java"
public class testing.AutoBoxing {
  public testing.AutoBoxing();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_5
       1: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       4: astore_1
       5: aload_1
       6: invokevirtual #3                  // Method java/lang/Integer.intValue:()I
       9: istore_2
      10: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
      13: aload_1
      14: invokevirtual #5                  // Method java/lang/Integer.toString:()Ljava/lang/String;
      17: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      20: return

但我不知道Open JDK使用的是什么。 會嘗試一下。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM