您好,登錄后才能下訂單哦!
這篇文章主要講解了“java中數組和集合的比較”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“java中數組和集合的比較”吧!
一、數組和集合的比較
數組不是面向對象的,存在明顯的缺陷,集合彌補了數組的缺點,比數組更靈活更實用,而且不同的集合框架類可適用不同場合。
如下:
1:數組能存放基本數據類型和對象,而集合類存放的都是對象的引用,而非對象本身!
2:數組容易固定無法動態改變,集合類容量動態改變。
3:數組無法判斷其中實際存有多少元素,length只告訴了數組的容量,而集合的size()可以確切知道元素的個數
4:集合有多種實現方式和不同適用場合,不像數組僅采用順序表方式
5:集合以類的形式存在,具有封裝、繼承、多態等類的特性,通過簡單的方法和屬性即可實現各種復雜操作,大大提高了軟件的開發效率
Collection和Map,是集合框架的根接口。 Collection的子接口:
Set:接口 ---實現類: HashSet、LinkedHashSet
Set的子接口SortedSet接口---實現類:TreeSet
List:接口---實現類: LinkedList,Vector,ArrayList
List集合
有序列表,允許存放重復的元素;
實現類:
ArrayList:數組實現,查詢快,增刪慢,輕量級;(線程不安全)
LinkedList:雙向鏈表實現,增刪快,查詢慢 (線程不安全)
Vector:數組實現,重量級 (線程安全、使用少)
ArrayList
底層是Object數組,所以ArrayList具有數組的查詢速度快的優點以及增刪速度慢的缺點。
而在LinkedList的底層是一種雙向循環鏈表。在此鏈表上每一個數據節點都由三部分組成:前指針(指向前面的節點的位置),數據,后指針(指向后面的節點的位置)。最后一個節點的后指針指向第一個節點的前指針,形成一個循環。
雙向循環鏈表的查詢效率低但是增刪效率高。
ArrayList和LinkedList在用法上沒有區別,但是在功能上還是有區別的。
LinkedList
LinkedList是采用雙向循環鏈表實現的。
利用LinkedList實現棧(stack)、隊列(queue)、雙向隊列(double-ended queue )。
它具有方法addFirst()、addLast()、getFirst()、getLast()、removeFirst()、removeLast()等。
經常用在增刪操作較多而查詢操作很少的情況下:
隊列和堆棧。
隊列:先進先出的數據結構。
棧:后進先出的數據結構。
注意:使用棧的時候一定不能提供方法讓不是最后一個元素的元素獲得出棧的機會。
Vector
(與ArrayList相似,區別是Vector是重量級的組件,使用使消耗的資源比較多。)
結論:在考慮并發的情況下用Vector(保證線程的安全)。
在不考慮并發的情況下用ArrayList(不能保證線程的安全)。
ArrayList自動擴充機制
實現機制:ArrayList.ensureCapacity(int minCapacity)
首先得到當前elementData 屬性的長度oldCapacity。
然后通過判斷oldCapacity和minCapacity參數誰大來決定是否需要擴容, 如果minCapacity大于
oldCapacity,那么我們就對當前的List對象進行擴容。
擴容的的策略為:取(oldCapacity * 3)/2 + 1和minCapacity之間更大的那個。然后使用數組拷
貝的方法,把以前存放的數據轉移到新的數組對象中
如果minCapacity不大于oldCapacity那么就不進行擴容。
用LinkedList實現隊列:
隊列(Queue)是限定所有的插入只能在表的一端進行,而所有的刪除都在表的另一端進行的線性表。
表中允許插入的一端稱為隊尾(Rear),允許刪除的一端稱為隊頭(Front)。
隊列的操作是按先進先出(FIFO)的原則進行的。
隊列的物理存儲可以用順序存儲結構,也可以用鏈式存儲結構。
用LinkedList實現棧:
棧(Stack)也是一種特殊的線性表,是一種后進先出(LIFO)的結構。
棧是限定僅在表尾進行插入和刪除運算的線性表,表尾稱為棧頂(top),表頭稱為棧底(bottom)。
棧的物理存儲可以用順序存儲結構,也可以用鏈式存儲結構。
List常用方法:
void add(int index, Object element) :添加對象element到位置index上
boolean addAll(int index, Collection collection) :在index位置后添加容器collection中所有的元素
Object get(int index) :取出下標為index的位置的元素
int indexOf(Object element) :查找對象element 在List中第一次出現的位置
int lastIndexOf(Object element) :查找對象element 在List中最后出現的位置
Object remove(int index) :刪除index位置上的元素
ListIterator listIterator(int startIndex) :返回一個ListIterator 跌代器,開始位置為startIndex
List subList(int fromIndex, int toIndex) :返回一個子列表List ,元素存放為從 fromIndex 到toIndex之前的一個元素
Set集合
擴展Collection接口
無序集合,不允許存放重復的元素;允許使用null元素
對 add()、equals() 和 hashCode() 方法添加了限制
HashSet和TreeSet是Set的實現
Set—》hashSet linkedHashSet
SortedSet —》 TreeSet
HashSet 的后臺有一個HashMap;初始化后臺容量;只不過生成一個HashSet的話,系統只提供key的訪問; 如果有兩個Key重復,那么會覆蓋之前的;
實現類 :
HashSet:equals返回true,hashCode返回相同的整數;哈希表;存儲的數據是無序的。
LinkedHashSet:此實現與 HashSet 的不同之外在于,后者維護著一個運行于所有條目的雙重鏈接列表。存儲的數據是有序的。
HashSet類 HashSet類直接實現了Set接口, 其底層其實是包裝了一個HashMap去實現的。HashSet采用HashCode算法來存取集合中的元素,因此具有比較好的讀取和查找性能。
HashSet的特征 不僅不能保證元素插入的順序,而且在元素在以后的順序中也可能變化(這是由HashSet按HashCode存儲對象(元素)決定的,對象變化則可能導致HashCode變化)
HashSet是線程非安全的
HashSet元素值可以為NULL
HashSet常用方法:
public boolean contains(Object o) :如果set包含指定元素,返回true
public Iterator iterator()返回set中元素的迭代器
public Object[] toArray() :返回包含set中所有元素的數組public Object[] toArray(Object[] a) :返回包含set中所有元素的數組,返回數組的運行時類型是指定數組的運行時類型
public boolean add(Object o) :如果set中不存在指定元素,則向set加入
public boolean remove(Object o) :如果set中存在指定元素,則從set中刪除
public boolean removeAll(Collection c) :如果set包含指定集合,則從set中刪除指定集合的所有元素
public boolean containsAll(Collection c) :如果set包含指定集合的所有元素,返回true。如果指定集合也是一個set,只有是當前set的子集時,方法返回true
實現Set接口的HashSet,依靠HashMap來實現的。
我們應該為要存放到散列表的各個對象定義hashCode()和equals()。
HashSet的equals和HashCode
前面說過,Set集合是不允許重復元素的,否則將會引發各種奇怪的問題。那么HashSet如何判斷元素重復呢?
HashSet需要同時通過equals和HashCode來判斷兩個元素是否相等,具體規則是,如果兩個元素通過equals為true,并且兩個元素的hashCode相等,則這兩個元素相等(即重復)。
幾種Set的比較:
HashSet外部無序地遍歷成員。
成員可為任意Object子類的對象,但如果覆蓋了equals方法,同 時注意修改hashCode方法。
TreeSet外部有序地遍歷成員;
附加實現了SortedSet, 支持子集等要求順序的操作
成員要求實現Comparable接口,或者使用Comparator構造
TreeSet。成員一般為同一類型。
LinkedHashSet外部按成員的插入順序遍歷成員
成員與HashSet成員類似
HashSet是基于Hash算法實現的,其性能通常都優于TreeSet。我們通常都應該使用HashSet,在我們需要排序的功能時,我們才使用TreeSet。
HashSet的元素存放順序和我們添加進去時候的順序沒有任何關系,而LinkedHashSet 則保持元素的添加順序。TreeSet則是對我們的Set中的元素進行排序存放。
一般來說,當您要從集合中以有序的方式抽取元素時,TreeSet 實現就會有用處。為了能順利進行,添加到 TreeSet 的元素必須是可排序的。 而您同樣需要對添加到TreeSet中的類對象實現 Comparable 接口的支持。一般說來,先把元素添加到 HashSet,再把集合轉換為 TreeSet 來進行有序遍歷會更快。
各種Set集合性能分析
HashSet和TreeSet是Set集合中用得最多的I集合。HashSet總是比TreeSet集合性能好,因為HashSet不需要額維護元素的順序。
LinkedHashSet需要用額外的鏈表維護元素的插入順序,因此在插入時性能比HashSet低,但在迭代訪問(遍歷)時性能更高。因為插入的時候即要計算hashCode又要維護鏈表,而遍歷的時候只需要按鏈表來訪問元素。
EnumSet元素是所有Set元素中性能最好的,但是它只能保存Enum類型的元素
Map
集合框架的第二類接口樹。
它提供了一組鍵值的映射。其中存儲的每個對象都有一個相應的關鍵字(key),關鍵字決定了對象在Map中的存儲位置。
關鍵字應該是唯一的,每個key 只能映射一個value。
實現類:
HashMap、TreeMap、LinkedHashMap、Hashtable等
HashMap:鍵值對,key不能重復,但是value可以重復;key的實現就是HashSet;value對應著放;允許null的鍵或值;
Hashtable:線程安全的,不允許null的鍵或值;
Properties::key和value都是String類型,用來讀配置文件;
TreeMap:對key排好序的Map; key 就是TreeSet, value對應每個key; key要實現Comparable接口或TreeMap有自己的構造器;
LinkedHashMap: 此實現與 HashMap 的不同之處在于,后者維護著一個運行于所有條目的雙重鏈接列表。存儲的數
據是有序的。
HashMap: Map 主要用于存儲鍵(key)值(value)對,根據鍵得到值,因此鍵不允許重復,但允許值重復。
HashMap 是一個最常用的Map,它根據鍵的HashCode 值存儲數據,根據鍵可以直接獲取它的值,具有很快的訪問速度。
HashMap最多只允許一條記錄的鍵為Null;允許多條記錄的值為 Null;
HashMap不支持線程的同步,即任一時刻可以有多個線程同時寫HashMap;可能會導致數據的不一致。如果需要同步,可以用 Collections的synchronizedMap方法使HashMap具有同步的能力。
HashMap實現原理---散列
Hash哈希算法的意義在于提供了一種快速存取數據的方法,它用一種算法建立鍵值與真實值之間的對應關系。散列表又稱為哈希表。散列表算法的基本思想是: 以結點的關鍵字為自變量,通過一定的函數關系(散列函數)計算出對應的函數值,以這個值作為該結點存儲在散列表中地址。
當散列表中的元素存放太滿,就必須進行再散列,將產生一個新的散列表,所有元素存放到新的散列表中,原先的散列表將被刪除。在Java語言中,通過負載因子(load factor)來決定何時對散列表進行再散列。例如:如果負載因子0.75,當散列表中已經有75%位置已經放滿,那么將進行再散列。
負載因子越高(越接近1.0),內存的使用效率越高,元素的尋找時間越長。負載因子越低(越接近0.0),元素的尋找時間越短,內存浪費越多。
何時需重寫equals?
當一個類有自己特有的“邏輯相等”概念(不同于對象身份的概念);
Object類僅僅提供了一個對引用的比較,如果兩個引用不是同一個那就返回false,這是無法滿足大多數對象比較的需要的,所以要覆蓋;
使用==操作符檢查實參是否為指向對象的引用”
使用instanceof操作符檢查實參是否為正確的類型
把實參轉換到正確的類型;
對于該類中每一個“關鍵”域,檢查實參中的域與當前對象中對應的域值是否匹 配。對于既不是float也不是double類型的基本類型的域,可以使用==操作符 進行比較;對于對象引用類型的域,可以遞歸地調用所引用的對象的equals方法,對于float和double類型的域,先轉換成int或long類型的值,然后使用==操作符比較;
當你編寫完成了equals方法之后,應該問自己三個問題:它是否是對稱的、傳 遞的、一致的? 如果答案是否定的,那么請找到 這些特性未能滿足的原因,再修改equals方法的代碼
equals()和hashCode()同時覆寫
尤其強調當一個對象被當作鍵值(或索引)來使用的時候要重寫這兩個方法;
覆寫equals后,兩個不同實例可能在邏輯上相等,但是根據Object.hashCode方法卻產生不同的散列碼,違反“相等的對象必須具有相等的散列碼”。
導致,當你用其中的一個作為鍵保存到hashMap、hasoTable或hashSet中,再以“相等的”找另 一個作為鍵值去查找他們的時候,則根本找不到
不同類型的hashCode取值
如果該域是布爾型的,計算(f?0:1)
如果是char,short,byte或int,計算(int)f
如果是long類型,計算(int)(f^(f>>>32))
如果是float類型,計算Float.floatToIntBits(f)
如果是double類型,計算Dobule.doubleToLongBits(f)
如果該域是一個對象引用,遞歸調用hashCode
如果該域是一個數組,則把每個元素當做單獨的域來處理,對每個重要的元素計算一個散列碼,
Map集合比較:
HashMap的存入順序和輸出順序無關。
LinkedHashMap 則保留了鍵值對的存入順序。
TreeMap則是對Map中的元素進行排序。
因為HashMap和LinkedHashMap 存儲數據的速度比直接使用TreeMap 要快,存取效率要高。
當完成了所有的元素的存放后,我們再對整個的Map中的元素進行排序。這樣可以提高整個程序的運行的效率,縮短執行時間。
注意:TreeMap中是根據鍵(Key)進行排序的。而如果我們要使用TreeMap來進行正常的排序的話,Key 中存放的對象必須實現Comparable 接口。
Map常用方法:
Object put(Object key,Object value):用來存放一個鍵-值對Map中
Object remove(Object key):根據key(鍵),移除鍵-值對,并將值返回
void putAll(Map mapping) :將另外一個Map中的元素存入當前的Map中
void clear() :清空當前Map中的元素
Object get(Object key) :根據key(鍵)取得對應的值
boolean containsKey(Object key) :判斷Map中是否存在某鍵(key)
boolean containsValue(Object value):判斷Map中是否存在某值(value)
public Set keySet() :返回所有的鍵(key),并使用Set容器存放
public Collection values() :返回所有的值(Value),并使用Collection存放
public Set entrySet() :返回一個實現 Map.Entry 接口的元素 Set
集合遍歷
1、增強for循環 for(Obj o:c){syso(o)}
2、使用iterator , Iterator it=c.iterator;
while(it.hasNext()){Object o = it.next()}
3、普通循環:for(Iterator it=c.iterator();it.hasNext();){it.next() }
感謝各位的閱讀,以上就是“java中數組和集合的比較”的內容了,經過本文的學習后,相信大家對java中數組和集合的比較這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。