1. 程式人生 > >ArrayList和List的使用區別

ArrayList和List的使用區別

最近在使用Java的過程中遇到了這個問題,啃了這篇文章後算是明白了!

原文連結:https://www.cnblogs.com/badtree/articles/5802299.html

這段時間在複習舊有的基礎知識,看到了泛型,裝箱,拆箱等操作。然後回憶起多年前一位面試官問起的一個問題,“你覺得ArrayList與List的有什麼使用上的區別”,當時我還是一個基礎知識好薄弱的碼農,只知道使用上的不同,完全不知道面試官想要考核的內容深度。

如果有一定基礎知道的朋友,一定好快會答得出這個問題的核心思想。就是效能

或許還會有一些做了很多年的程式設計師的朋友,仍然弄不清當中意義,正好今天心血來潮,就簡單的總結一下。

 

首先名詞解釋:

裝箱:在值型別向引用型別轉換時發生;

拆箱:在引用型別向值型別轉換時發生;

值型別:直接將記憶體儲存在棧內,由系統自動釋放資源的資料型別;

引用型別:由型別的實際值引用(類似於指標)表示的資料型別,通俗點說就是在程式設計時需要new出來的變數型別都是引用型,引用型別是存放在記憶體的堆中;

記憶體堆跟棧的定義跟資料結構的堆疊是不同的,其實網上也有很多的解釋,我在這裡就通俗的給大家說一下。

棧:由大至小的分配,先進後出,直接存放值型別的地方;我們一般出現的記憶體溢位就是由於棧位都分配完了;

堆:由小至大的分配,隨意儲存,存放引用型別的地方;

C#的值型別(在C#中所有的值型別都繼承自:System.ValueType)
整型:Int;
長整型:long;
浮點型:float;
字元型:char;
布林型:bool;
列舉:enum;
結構:struct;

 

看了這麼多的名詞解釋,我們再回到最初的話題ArrayList與List的使用區別。

 

先看ArrayList的使用:

public void ArrayListDemo()
{
  ArrayList list = new ArrayList();
  list.add(1);
  list.add(2);
  
  foreach(int i in list)
  {
    Console.WriteLine("value is {0}", value);
  }
}

由於ArrayList的每個item預設是Object的型別,所以當我們執行語句list.add(1);的時候,就是做了一次裝箱的操作。同理,在for迴圈裡list的每一項都要做一個拆箱的操作才能得到變數i,最後到列印變數i時,由於字串也是引用型別,所以也要做一次的裝箱的操作。這裡前後一共做了6次的裝箱拆箱(4次裝箱,2次拆箱),每一次的裝箱拆箱都涉及CPU以及記憶體的分配,都是效能的損耗。

由.net2.0開始,就引入了泛型這個很好用的東西,下面看看List的使用:

public void ListDemo()
{
  List<int>list = new List<int>();
  list.add(1);
  list.add(2);

  foreach(int i in list)
  {
    Console.WriteLine("value is {0}", value);
  }
}

由於List使用了泛型,我們指定了item必需是int型別,所以在add item的時候,不需要再進行裝箱拆箱的操作,一直到列印i的時候,才需要做裝箱的操作,整段程式碼執行完以後,一共才進行2次的裝箱拆箱(2次裝箱,0次拆箱)。

如果List的item多,程式執行時,相對於ArrayList來說就會節省很多的系統資源。所以List與ArrayList的使用區別,到最後就是效能的表現問題,但其中的原理,看完上面的介紹,相信如果有人再問你,你會很容易的回答出來。

 

最後順帶一提,.net的泛型與Java的泛型是不一樣的,雖然都叫泛型,但.net對泛型的型別指定在編譯執行時是不會取消的,所以大大減少了型別轉換(裝箱拆箱)的操作,而Java在編譯時泛型的型別指定是移除了,所以即使編碼時指定了相關型別,但執行時依然要進行型別轉換(裝箱拆箱)的操作,效能沒有得到提升。雖然如此,泛型除了提高執行效能外,還有其它的用途,例如增加程式的可讀性,增加程式的程式設計安全性等。所以即使在Java中使用泛型沒有得到效率的提升,但無論在程式設計的習慣上,還是提高程式碼的質量上都提倡使用泛型。