2010-01-25 342 views
27

在很高的層次上,我知道我們需要使用它們各自的包裝類在Java集合中使用它們來「包裝」原始數據類型,例如int和char。我想了解Java集合如何工作在低級別問:「爲什麼我們需要將原始數據類型包裝爲對象以便能夠在集合中使用它們?」我事先感謝您的幫助。Java:爲什麼需要包裝類?

+0

可能的重複[爲什麼Java中有包裝類?](http://stackoverflow.com/questions/3579035/why-are-there-wrapper-classes -in-java) – nbro 2015-01-01 20:25:56

回答

18

在虛擬機級別,這是因爲與引用類型(如java.lang.Object及其派生類型)相比,基本類型在內存中的表示方式非常不同。例如Java中的基本int在內存中只有4個字節,而一個Object本身至少佔用8個字節,再加上另外4個字節來引用它。這種設計是CPU可以更有效地處理原始類型這一事實的簡單反映。

所以你的問題「爲什麼需要包裝類型」的一個答案是因爲它使能的性能改進。

但是對於程序員來說,這樣的區分會增加一些不受歡迎的認知開銷(例如,不能在集合中使用int和float)。實際上,通過隱藏這種區別很可能進行語言設計---許多腳本語言做到這一點,CLR就是這麼做的。從1.5開始,Java也是如此。這是通過讓編譯器以靜默方式在原始表示和對象表示之間插入必要的轉換(通常稱爲裝箱/拆箱)來實現的。)

所以另一個回答你的問題是,「不,我們不需要它」,因爲編譯器會自動爲你,並在一定程度上你可以忘記這是怎麼回事幕後。

+1

您可以詳細說明基本類型和引用類型是如何通過JVM存儲在內存中的嗎? – 2010-01-25 19:18:48

+2

@Midnight Blue - 閱讀第一個答案(作者:Jon Skeet):http://stackoverflow.com/questions/2099695/java-array-is-stored-in-stack-or-heap。它更詳細地解釋了事物如何存儲在JVM中以及何時存儲。 – 2010-01-25 19:23:00

+0

@Justin N. - 感謝您的鏈接 – 2010-01-25 19:26:22

31

由於Java集合只能存儲對象引用(因此您需要將基元存儲在集合中)。

閱讀關於Autoboxing的此短文,瞭解更多信息。

如果你想在細節堅韌的細節,它幾乎可以歸結爲以下幾點:

本地原語存儲在堆棧。 Collections通過對Heap中Object的內存位置的引用來存儲它們的值。爲了獲得一個本地基元的引用,你必須將該值(堆棧上的值並將其包裝在Heap上存儲)。

3

原始數據類型不能作爲內存地址引用。這就是爲什麼我們需要用作原始值的佔位符的包裝器。這些值可以被突變和訪問,重組,排序或隨機化。

+1

咦? Java沒有指針。 – BalusC 2010-01-25 19:11:07

+1

你寫道:「這些值然後可以變異」。對於Java中的原始對象包裝器,這實際上並不正確。它們都是不變的。 – Asaph 2010-01-25 19:13:53

+0

引用基本上是一個指針,只是更多一點限制。在我看來,他們應該把它稱爲指針而不是引用,因爲「參考」這個術語非常具有誤導性。 – helpermethod 2010-01-25 19:23:35

1

那麼,原因是Java集合沒有區分原始對象和對象。它將它們全部處理爲Object,因此它將需要一個包裝器。您可以輕鬆構建自己的不需要包裝的集合類,但最終必須爲每個類型char,int,float,double等構建一個乘以集合類型(Set,Map,列表,及其實施)。

你能想象這是多麼無聊嗎?實際上,它對於大多數應用程序使用無包裝的性能幾乎可以忽略不計。然而,如果你需要非常高的性能,一些原始集合的庫也可用(例如http://www.joda.org/joda-primitives/

+0

集合的區分非常好:如果您嘗試使用java基元,它們可以很好地處理對象併爲編譯錯誤打耳光! – 2010-01-25 19:24:17

4

要將集合類中的基元類型值存儲,我們需要包裝類。

1

收藏以泛型爲基礎。 Collection Framework旨在收集,存儲和操作任何類的數據。所以它使用泛型類型。通過使用泛型,它能夠存儲您的聲明中指定名稱的ANY CLASS的數據。

現在,我們在其中要原始數據存儲在其中收集的工作方式相同的方式不同的場景。我們無法使用ArrayList,HashSet等Collection類來存儲原始數據,因爲Collection類只能存儲對象。因此,爲了在Collection中存儲基本類型,我們提供了包裝類。

0

包裝類提供了與相應數據類型相關的有用方法,您可以在某些情況下使用相應的數據類型。

一個簡單的例子。考慮一下,

Integer x=new Integer(10); 
//to get the byte value of 10 
x.byteValue(); 

//but you can't do this, 
int x=10; 
x.byteValue(); //Wrong! 

你能明白這一點嗎?

0

如果已知某個變量保持代表null的特定位模式或可用於查找Java虛擬機對象頭的信息,並且讀取給定引用的對象頭的方法將固有地陷入如果考慮到與null相關聯的位模式,那麼JVM可以在假設有一個的情況下訪問變量所標識的對象。如果一個變量可能包含某些不是有效引用但不是特定位模式的東西,則任何試圖使用該變量的代碼都必須首先檢查它是否標識了一個對象。這會大大減慢JVM。

如果ObjectAnything衍生,並從Object派生類對象,而是來自Anything派生不同的類繼承的原語,然後在64位實現它可能是實際地說,可能的比特的約3/4圖案將代表double值低於2^512,它們中的1/8來表示範圍+/- 1,152,921,504,606,846,975 long值,數十億表示任何其他primitve的任何可能的值,並且1/256來識別對象。對Anything類型的東西的多種操作將比Object類型的操作要慢,但這種操作不會非常頻繁;在嘗試使用它之前,大多數代碼最終會將Anything轉換爲更具體的類型;存儲在Anything中的實際類型將需要在投射前進行檢查,但在演員執行後不需要進行檢查。然而,如果沒有區分引用堆類型的變量,而不是區分持有「任何」引用的變量,那麼將無法避免使開銷遠遠超過其他方法或應該進行的延伸。

0

很像String類,包裝器提供額外的功能,並啓用程序員做更多的數據存儲的過程。所以,以同樣的方式的人使用String類一樣....

String uglyString = "fUbAr"; String myStr = uglyString.toLower();

也是如此,它們可以與包裝。類似的想法。

這是除了Bharat上面提到的集合/泛型的打字問題外。

0

閱讀所有的答案,但沒有一個真正解釋它只是通俗的術語。

包裝類包裝(封裝)圍繞一個數據類型(可以是任何原始數據類型如int,焦炭,字節長),並使其成爲一個對象

這裏有幾個原因需要包裝類:

  1. 允許null值。
  2. 可以在收集諸如ListMap使用等
  3. 能在它接受Object類型的參數的方法中使用。

    Integer wrapperInt = new Integer("10"); 
    
  4. 使所有可用的函數Object類具有諸如clone()equals()hashCode()toString()

包裝器類:

  • 能像使用new ClassName()像其他對象的對象被創建可以通過兩種方式創建:

    1. 使用構造函數:

      Integer i = new Integer("1"); //new object is created 
      
    2. 使用valueOf()靜態運營商:

      Integer i = Integer.valueOf("100"); //100 is stored in variable 
      

    它建議使用創建的包裝類的第二種方式,因爲它需要較少的內存作爲新對象未創建。

  • 0

    因爲int不屬於任何類。 我們將數據類型(int)轉換爲對象(Interger)

    相關問題