歡迎查看List、Set、Map

List、Set、Map各自的特點

一、結構特點

(一)list

1、實現了collection接口
2、允許重複的對象
3、可以有多個空值
4、裏邊元素有序(即爲每個元素的插入順序)
5、單列數據集合
6、實現類ArrayList、LinkedList 、Vector

(二)Set

1、實現了collection接口
2、元素唯一,不保存重複元素。
3、允許出現空值(只能有一個)
4、單列數據集合
5、元素位置固定(由hashcode決定)
6、元素無序(指不按照用戶輸入的順序排序)
7、實現類HashSet、TreeSet、LinkedHashSet、SortedSet等

(三)Map

1、Map是存儲鍵值對這樣的雙列數據的集合;(key,value)
2、Map中存儲的數據是無序(按照hashcode來排的)
3、鍵不允許重複,值可用重複
4、鍵只能有一個null,值可用有多個null
5、實現類HashMap、HashTable、LinkedHashMap等
總結: List單列集合,元素:有序、可重複、可爲空;
    Set單列集合,元素:無序、不重複、只有一個空元素;
    Map單列集合,元素:無序、鍵不重,值可重、可一個空鍵、多可空值;

二、實現類

(一)List接口有三個實現類

    1 LinkedList
    基於鏈表實現,鏈表內存是散列的,增刪快,查找慢;
    2 ArrayList
    基於數組實現,非線程安全,效率高,增刪慢,查找快;
    3 Vector
基於數組實現,線程安全,效率低,增刪慢,查找慢;

(二)Map接口有四個實現類

 1 、HashMap
 基於 hash 表的 Map 接口實現,非線程安全,高效,支持 null 值和 null
 鍵;
 2 、HashTable
 線程安全,低效,不支持 null 值和 null 鍵;
 3 、LinkedHashMap
 是 HashMap 的一個子類,保存了記錄的插入順序;
 4 、SortMap 接口
 5、TreeMap,能夠把它保存的記錄根據鍵排序,默認是鍵值的升序排序

(三) Set接口有兩個實現類

1 HashSet
底層是由 Hash Map 實現,不允許集合中有重複的值,使用該方式時需要重寫 equals()和 hash Code()方法;
2 LinkedHashSet
繼承於 HashSet,同時又基於 LinkedHashMap 來進行實現,底層使用的是 LinkedHashMap

三、List、Set、Map區別

  1. List 集合中對象按照索引位置排序,可以有重複對象,允許按照對象在集合中的索引位置檢索對象,例如通過list.get(i)方法來獲取集合中的元素;
  2. Map 中的每一個元素包含一個鍵和一個值,成對出現,鍵對象不可以重複,值對象可以重複;
  3. Set 集合中的對象不按照特定的方式排序,並且沒有重複對象,但它的實現類能對集合中的對象按照特定的方式排序,例如 Tree Set 類,可以按照默認順序,也可以通過實現 Java.util.Comparator< Type >接口來自定義排序方式。

四、補充知識

(一)、HashMap 和 HashTable的區別?

1、HashMap 是線程不安全的,HashMap 是一個接口,是 Map的一個子接口,是將鍵映射到值得對象,不允許鍵值重複,允許空鍵和空值;由於非線程安全, HashMap的效率要較 HashTable 的效率高一些。HashMap的初始容量和負載因子決定,初始容量16,負載因子0.75。噹噹前大小和當前容量的比例超過了擴容因子,就會擴容,擴容後大小爲 一倍。即每次爲2n
2、HashTable 是線程安全的一個集合,不允許 null 值作爲一個 key 值或者 Value 值;HashTable 是 sychronize(同步化),多個線程訪問時不需要自己爲它的方法實現同步,而 HashMap 在被多個線程訪問的時候需要自己爲它的方法實現同步; 目前不用HashTable,需要線程安全時候用ConcurrentHashMap(分段鎖)替代HashTable。HashTable初始容量爲11,每次擴容2n+1

(二)HashMap和HashSet的區別

在這裏插入圖片描述

(三)ArrayList和LinkedList的區別

答:ArrayList的底層數據結構爲數組,增刪慢、查詢快,線程不安全,效率高。
LinkedList的底層數據結構爲鏈表,增刪快、查詢慢,線程不安全,效率高。
備註:一個對象可以被反覆存儲進List中,每調用一次add方法,這個對象就被插入進集合中一次,其實,並不是把這個對象本身存儲進了集合中,而是在集合中用一個索引變量指向這個對象,當這個對象被add多次時,即相當於集合中有多個索引指向了這個對象。

(四)ArrayList與Vector的區別?

答:Vector底層數據結構爲數組,增刪慢、查詢快,線程安全,效率低,每次擴容爲原來數組的2倍。
ArrayList底層數據結構爲數組,增刪慢、查詢快,線程不安全,效率高,每次擴容爲原來數組的1.5倍。

(五) ArrayList的底層是數組,數組的名稱是什麼?類型是什麼?

答:名稱是elementData,類型是Object[],所以ArrayList裏面可以存放任意類型的元素。

(六) ArrayList底層數組的默認初始化容量是多少?當超出這個大小時,每次擴容是多少?

答:默認初始化容量是10。當超出這個大小時,每次擴容1.5倍。

(七)當向ArrayList集合中添加元素時需要調用add()方法,add()方法的執行流程是怎樣的?

答:調用add()方法時,add()方法首先調用ensureCapacityInternal()來判斷elementData數組容量是否足夠,ensureCapacityInternal()之所以能夠判斷,是因爲它內部調用了ensureExplicitCapacity()方法,這個方法纔是真正判斷elementData數組容量是否夠用的關鍵方法。如果容量足夠,則直接將元素添加到ArrayList中;如果容量不夠,則ensureExplicityCapacity()方法內部會調用grow()方法來對數組進行擴容。擴容成功之後,再將元素添加到ArrayList擴容之後的新數組中。

(八)在調用ArrayList的remove(int index)方法時,執行流程是怎樣的?

答:首先判斷index是否合理,如果合理的話,會調用System.arraycopy()方法把指定下標到數組末尾的元素向前移動一個單位,並且會把數組最後一個元素設爲null。這樣是爲了方便GC回收。

(九) ArrayList在調用get(int index)方法查詢的時候,執行流程是怎樣的?

答:首先判斷index是否合理,然後調用elementData()方法,elementData()方法返回根據index查到的具體的元素。注意:這裏的返回值都經過了向下轉型(Object -> E)。

(十)ArrayList的大小是如何自動增加的?你能分享一下你的代碼嗎?

答:當向ArrayList中增加一個對象的時候,Java首先會判斷ArrayList的底層數組elementData是否還有足夠的空間來存儲這個對象,如果有,就直接存,如果沒有,就會基於原有的數組擴容出一個1.5倍的新數組,並將數據全部複製到新數組中。
注意:新建了一個數組,舊數組的對象被複制到了新的數組中,並且現有的數組引用指向新的數組。

(十一)什麼情況下你會使用ArrayList?什麼情況下你會選擇LinkedList?

答:當對數據的主要操作爲索引或只在集合的末端增加、刪除數據時,使用ArrayList效率比較高;當對數據的操作主要爲指定位置的插入或刪除操作時,使用LinkedList效率比較高。

(十二). ArrayList的時間複雜度是多少?

答:當修改、查詢或者只在數組末尾增、刪時,時間複雜度爲O(1);對指定位置的元素進行增、刪時,時間複雜度爲O(n)。

(十三)HashSet中調用add()時不允許重複原理

答:HashSet底層由HashMap實現,插入的元素被當做是HashMap的key,value默認爲一個固定的Object,根據hashCode值來確定在集合中的位置,在添加元素時,先判斷key的hashCode值是否相同,如果相同,則調用equals()、==進行判斷,若相同則覆蓋原有元素;如果不同,則直接向Map中添加元素;

(十四)HashMap執行put()方法時候的原理

答:
情況一:調用該元素鍵的equals方法與該位置上元素的鍵進行比較,如果返回ture則視新鍵與已經存在的鍵相同,用新值去更新舊值,然後put方法返回舊值
情況二:調用該元素鍵的equals方法與該位置上元素的鍵進行比較,如果返回false則新鍵與已經存在的鍵不相同,任然可以將新的元素存儲在該位置。

五、List、set、Map的遍歷

(一)遍歷形式

list可用for、forEach、Iterator遍歷
Set只能用迭代器遍歷
Map可用for、forEach、Iterator遍歷

(二)數組轉換爲集合在用迭代器輸出

Int [] ={1,2,3,4,5,6};
List list=new ArrayList(Arrays.asList(arr));
Iterator it=list.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}

(三)遍歷Map的方式

Map<Integer,String> map = new HashMap<Integer,String>();

方式一:只能遍歷value,不能遍歷key

//		System.out.println(m.size());
//		for(String s:m.values()) {
//			System.out.println(s);
//		}

方式二:(推薦使用,尤其在大量數據操作的時候)

//		for(Map.Entry<Integer, String> v:m.entrySet()) {
//			System.out.println("鍵:"+v.getKey()+","+"值:"+v.getValue());
//		}

方式三:使用map中的entrySet()方式,將map轉換爲set利用迭代器迭代

//		Iterator<Entry<Integer, String>>  map1it=m.entrySet().iterator();
//        while(map1it.hasNext())
//        {
//         Map.Entry<Integer, String> entry=(Entry<Integer, String>) map1it.next();
//         System.out.println("Key: "+entry.getKey()+" Value: "+entry.getValue());
//        }

方式四:根據key二次取值,

//        for(Integer key:m.keySet()) {
//        	System.out.println("鍵:"+key+","+"值:"+m.get(key));
//        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章