第7節:Java基礎 - 三大集合(下)

 

(1) TreeMap有哪些特徵

答:TreeMap底層實現使用紅黑樹實現,TreeMap中存儲的鍵值對按照鍵來排序

  • 如果Key存入的是字符串等類型,那麼會按照字典序默認排序

  • 如果傳入的是自定義引用類型,比如說User,那麼該對象必須實現Comparable接口,並且覆蓋其compareTo,或者在創建TreeMap的時候,我們必須指定使用的比較器

    // 方式一:定義該類的時候,就指定比較規則
    class User implements Comparable{
        @Override
        public int compareTo(Object o) {
            // 在這裏邊定義其比較規則
            return 0;
        }
    }
    public static void main(String[] args) {
        // 方式二:創建TreeMap的時候,可以指定比較規則
        new TreeMap<User, Integer>(new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                // 在這裏邊定義其比較規則
                return 0;
            }
        });
    }
    

    解析

    ​ 關於TreeMap的考察,會涉及到兩個接口Comparable和Comparator的比較。Comparable接口的後綴able大概表示可以的意思,也就是說一個類如果實現了這個接口,那麼這個類就是可以比較的。類似還有cloneable接口表示可以克隆的。而Comparator則是一個比較器,是創建TreeMap的時候傳入,用來指定比較規則。

    Comparaable接口和Comparator接口的區別

    • Comparable實現比較簡單,但是當需要重新定義比較規則的時候,必須修改代碼,即修改User類裏邊的compareTo方法

    • Comparator接口不需要修改源代碼,只需要在創建TreeMap的時候重新傳入一個具有指定規則的比較器即可。

    (2)ArrayList和LinkedList的區別

    常用的ArrayList和LinkedList的區別如下:

    • ArrayList底層實現使用了動態數組實現,實質上是一個動態數組

    • LinkedList底層實現使用了雙向鏈表實現,可當作堆棧,隊列,雙端隊列使用

    • ArrayList在隨機存取方面效率高於LinkedList

    • LinkedList在節點的增刪方面效率高於ArrayList

    • ArrayList必須預留一定的空間,當空間不足的時候,會進行擴容操作

    • LinkedList的開銷是必須存儲節點的信息以及節點的指針信息

    解析:

    ​ List集合也是我們平時使用很多的集合。List接口的長劍實現就算ArrayList和LinkedList,我們必須熟練掌握其底層實現以及一些特徵。其實好友一個集合Vector,它是線程安全的ArrayList,但是已經被廢棄,不推薦使用了。多線程環境下,我們可以使用CopyOnWriteArrayList替代ArrayList來保證線程安全。

    (3)HashSet和TreeSet的區別

     

    HashSet和TreeSet的區別:

    • HashSet底層實現使用了Hash表實現。(保證元素唯一性原理:判斷元素的hashCode值是否相同。如果相同,還會繼續判斷元素的equals方法,是否爲true)

    • TreeSet底層使用了紅黑樹來實現。(保證元素唯一性是通過Comparable和Comparator接口實現)

    解析

    其實,HashSet的底層實現還是HashMap,只不過其使用了其中的Key,具體如下所示:

    • HashSet的add方法底層使用HashMap的put方法將key = e,value=PRESENT構建成key-value鍵值對,當此e存在於HashMap的key中,則value將會覆蓋原有value,但是key保持不變,所以如果將一個已經存在的e元素添加到HashSet中,新添加的元素是不會保存到HashMap中,所以就滿足了HashSet中元素不會重複的特性。

    • HashSet的contains方法使用HashMap的containsKey方法實現

    (4)LinkedHashMap和LinkedHashSet有了解嗎?

    LinkedHashMap可以記錄下元素的插入順序和訪問順序,具體實現如下:

    • LinkedHashMap內部的Entry繼承於HashMap.Node,這兩個類都實現了Map.Entry<K,V>

    • LinkedHashMap的Entry不光有value,next,還有before和after屬性,這樣通過一個雙向鏈表,保證了各個元素的插入順序

    • 通過構造方法public LinkedHashMap(int initialCapacity,float loadFactor,boolean accessOrder), accessOrder傳入true可以實現LRU緩存算法(訪問順序)

    • LinkedHashSet 底層使用LinkedHashMap實現,兩者的關係類似與HashMap和HashSet的關係,大家可以自行類比。

     

    擴展: 什麼是LRU算法?LinkedHashMap如何實現LRU算法?

    LRU(Least recently used,最近最少使用)算法根據數據的歷史訪問記錄來進行淘汰數據,其核心思想是“如果數據最近被訪問過,那麼將來被訪問的機率也更高”。

    由於LinkedHashMap可以記錄下Map中元素的訪問順序,所以可以輕易的實現LRU算法。只需要將構造方法的accessOrder傳入true,並且重寫removeEldestEntry方法即可。具體實現參考

    package pak2;
     
    import java.util.LinkedHashMap;
    import java.util.Map;
     
    public class LRUTest {
     
        private static int size = 5;
     
        public static void main(String[] args) {
            Map<String, String> map = new LinkedHashMap<String, String>(size, 0.75f, true) {
                @Override
                protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
                    return size() > size;
                }
            };
            map.put("1", "1");
            map.put("2", "2");
            map.put("3", "3");
            map.put("4", "4");
            map.put("5", "5");
            System.out.println(map.toString());
     
            map.put("6", "6");
            System.out.println(map.toString());
            map.get("3");
            System.out.println(map.toString());
            map.put("7", "7");
            System.out.println(map.toString());
            map.get("5");
            System.out.println(map.toString());
        }
    }
    

      

    (5)List和Set的區別?

    • List是有序的並且元素是可以重複

    • Set是無序(LinkedHashSet除外)的,並且元素是不可以重複(此處的有序和無序是指放入順序和取出順序是否保持一致)

    (6)Iterator和ListIterator的區別是什麼?

    • Iterator可以遍歷list和set集合;ListIterator只能用來遍歷list集合

    • Iterator前者只能前向遍歷集合;ListIterator可以前向和後向遍歷集合

    • ListIterator其實就是實現了前者,並且增加了一些新的功能。

    解析:

    Iterator其實就是一個迭代器,在遍歷集合的時候需要使用。Demo實現如下:

    ArrayList<String> list =  new ArrayList<>();
    list.add("zhangsan");
    list.add("lisi");
    list.add("yangwenqiang");
    // 創建迭代器實現遍歷集合
    Iterator<String> iterator = list.iterator();
    while(iterator.hasNext()){
        System.out.println(iterator.next());
    }
    

      

    (7)數組和集合List之間的轉換:

    package niuke;
     
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
     
    public class ConverTest {
        public static void main(String[] args) {
            // list集合轉換成數組
            ArrayList<String> list =  new ArrayList<>();
            list.add("zhangsan");
            list.add("lisi");
            list.add("yangwenqiang");
            Object[] arr = list.toArray();
            for (int i = 0; i < arr.length; i++) {
                System.out.println(arr[i]);
            }
            System.out.println("---------------");
            // 數組轉換爲list集合
            String[] arr2 = {"niuke", "alibaba"};
            List<String> asList = Arrays.asList(arr2);
            for (int i = 0; i < asList.size(); i++) {
                System.out.println(asList.get(i));
            }
     
        }
    

    輸出結果如下:

     

     

     

     

    解析:

    關於數組和集合之間的轉換是一個常用操作,這裏主要講解幾個需要注意的地方吧。

    數組轉爲集合List:

    通過Arrays.asList方法搞定,轉換之後不可以使用add/remove等修改集合的相關方法,因爲該方法返回的其實是一個Arrays的內部私有的一個類ArrayList,該類繼承於Abstractlist,並沒有實現這些操作方法,調用將會直接拋出UnsupportOperationException異常。這種轉換體現的是一種適配器模式,只是轉換接口,本質上還是一個數組。

    集合轉換數組:

    List.toArray方法搞定了集合轉換成數組,這裏最好傳入一個類型一樣的數組,大小就是list.size()。因爲如果入參分配的數組空間不夠大時,toArray方法內部將重新分配內存空間,並返回新數組地址;如果數組元素個數大於實際所需,下標爲list.size()及其之後的數組元素將被置爲null,其它數組元素保持原值。所以,建議該方法入參數組的大小與集合元素個數保持一致。

    若是直接使用toArray無參方法,此方法返回值只能是Object[ ]類,若強轉其它類型數組將出現ClassCastException錯誤。

    (8)Collection和Collections有什麼關係?

    這是Java中的一類問題,類似的還有Array和Arrays,Executor和Executors有什麼區別與聯繫? (待補)

    附圖:

    集合的類圖:

    我們接着給出本節所涉及到的集合的類圖結構:(C表示這是一個類,I表示這是一個接口)

    • TreeMap的類圖結構:

       

       LinkedHashMap的類圖結構:

       

       ArrayList的類圖結構

    •  

       LinkedList的類圖結構:

       

       

      Vector的類圖結構:

       

       HashSet的類圖結構:

       

       

      TreeSet的類圖結構:

       

       

       

       

       

       

       

發佈了675 篇原創文章 · 獲贊 30 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章