JAVA——集合理解

集合複習

一.集合就像一種容器,可以動態的把多個對象的引用

放入到容器中,存儲多個數據 。

集合數組都是對多個數據進行存儲操作的結構,簡稱java容器

二、集合框架、

collection接口:單列集合,用來存儲一個一個對象

​ list接口:存儲有序可重複的數據

​ 實現類:ArrayList LinkedList

​ set接口:存儲無序,不可重複的數據

​ 實現類:HashSet

map接口:雙列集合,用來存儲一對一對的數據

​ 實現類:HashMap

三、collection(爲什麼不用collection? 因爲即有序又無序,即可重複,又不可重複,找不到這樣的容器,所以纔會用List和Set)

collection的方法:(需要重寫元素所在類的equals方法)

  1. add() //添加元素,可以爲簡單類型,和引用類型 ,返回boolean

    Collection coll=new ArrayList();
           coll.add("aa");
  2. addAll(Collection c)//添加集合數據
    Collection coll=new ArrayList();
    Collection coll1=new ArrayList();
    coll1.add("bb");
    coll.addAll(coll1);
  3. clear() //清空集合
    Collection coll=new ArrayList();
    coll.add("aa");
    coll.clear();
  4. isEmpty() // 判斷是否爲空,沒有元素
    Collection coll=new ArrayList();
    coll.add("aa");
    coll.clear();
    coll.isEmpty();
  5. contains(Object obj)// 是否包含一個對象,判斷的是其內容,內容一致則結果爲true,內容不一致則結果爲false,這裏對於String類型,其equals方法已經重寫了,故而只需要判斷內容是否一致即可,但是對於JAVA BEAN類型,需要重寫其equals方法,否則會判斷爲false。 可看代碼後的總結

    例如:

    private String name;
    private int age;
    public Person() {
       }
    
       public Person(String name, int age) {
           this.name = name;
           this.age = age;
       }
    
       public String getName() {
           return name;
       }
    
       public void setName(String name) {
           this.name = name;
       }
    
       public int getAge() {
           return age;
       }
    
       public void setAge(int age) {
           this.age = age;
       }
    
       @Override
       public String toString() {
           return "Person{" +
                   "name='" + name + '\'' +
                   ", age=" + age +
                   '}';
       }
    //重寫equals方法,如果不寫,則結果爲false
       @Override
       public boolean equals(Object o) {
           System.out.println("kaishi l ");
           if (this == o) return true;
           if (o == null || getClass() != o.getClass()) return false;
           Person person = (Person) o;
           return age == person.age &&
                   Objects.equals(name, person.name);
       }
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.Date;
    
    public class Demo {
       public static void main(String[] args) {
           Collection coll=new ArrayList();
           coll.add("aa");
           coll.add("bb");
           System.out.println(coll.contains("aa"));//true ,判斷是否有aa,有,則爲true
    
           coll.add(new String ("huhu"));
           System.out.println(coll.contains(new String("huhu")));//結果爲true,因爲string底層已經把equals重寫過了,直接判斷內容
    
           coll.add(new Person("wwuu",123));
           System.out.println(coll.contains(new Person("wwuu",123)));//因爲上面已經對Person對象進行重寫了equals方法,這裏直接判斷是否有wuwu,123.有則爲true
           //如果上面沒有對Person對象的equals方法進行重寫,那麼這裏爲false
           //總結:contains比較的是內容,等於用equals方法進行比較
           //我們在判斷時,會調用obj對象所在類的equals()方法,故而obj所在類要重寫equals()方法。
       }
    }
    
  6. containsAll(Collection coll1)//判斷coll集合中的所有元素是否都存在於當前集合中(注意是:所有元素,但凡有一個不在,則爲false)
    Collection coll=new ArrayList();
    Collection coll1=new ArrayList();
    coll.add("123");
    coll1.add("haha");
    coll.addAll(coll1);
    System.out.println(coll.containsAll(coll1));//true,上面用了addAll()方法,把coll1中的數據都放到了coll中,所以coll包含了coll1,爲true
    coll1.add("uiui");
    System.out.println(coll.containsAll(coll1));//false,這裏是因爲coll1新加了一條數據,而coll中沒有這條數據,故而爲false
  7. remove(Object obj) (刪除某個元素,重寫元素所在類的equal()方法)
    coll.remove(new Person("wwuu",123));
    System.out.println(coll);//由於上述的方法中已經對Person這個類進行了equals()方法的重寫,故而這裏是可以對new Person("wwuu",123)這個元素進行刪除的,如果不重寫equals方法則刪除不了
  8. remoeAll(Collection coll)(刪除coll中所有的元素,重寫元素所在類的equal()方法)
    coll.removeAll(coll1);
    System.out.println(coll1);
    System.out.println(coll);
  9. retainAll(Collection coll)(求交集的意思,僅僅保留當前集合中的元素並且該元素同時也在另一個集合中,即獲取當前集合與coll的交集,重寫元素所在類的equal()方法)
    
    Collection coll2=new ArrayList();
           coll2.add(123);
           coll2.add(new String ("huhu"));
           coll2.add(new String("bb"));
           coll.retainAll(coll2);
           System.out.println(coll);
  10. equals(Object o) (這裏是判斷兩個集合是否相等,那麼這裏的obj必須是集合才行,也要重寫元素所在類的equals()方法。對於有序集合,其位置也不必須相同,若爲無序集合,其位置可以不同,只需要元素相等即可。)
    Collection coll3= Arrays.asList(123,"huhu","bb");
    System.out.println(coll2.equals(coll3));
  11. hashCode() (計算機hashCode哈希值的方法,返回值是int)
    System.out.println(coll3.hashCode());
  12. toArray() (集合轉數組)
    Object[] objects = coll3.toArray();
            for (Object o: objects) {
                System.out.println(o);
            }
    拓展一下:數組轉集合(使用的時候注意 Arrays.asList(T)的參數是可變形參,根據不同需要看是寫int 還是其包裝類integer ,int會判斷成爲一個參數,integer爲兩個參數)
    List list2 = Arrays.asList(new int[]{123, 455});
    List list3 = Arrays.asList(new Integer[]{123, 455});
    System.out.println(list2.size());//結果是1,判斷一個參數
    System.out.println(list3.size());//結果是2,判斷2個參數
  13. iterator()(迭代器接口:遍歷集合的時候使用)
    Iterator iterator=coll2.iterator();
    while (iterator.hasNext()){
           System.out.println(iterator.next());
    }
    拓展:內部定義了一個remove方法,可以刪除集合中的元素
  14. foreach
    foreach(Object obj: coll2){
        System.out.println(obj);
    }

LIst----有序可重複(俗稱:動態數組)

他是一個接口,通常用List代替數組,有三個實現類ArrayList、LinkedList、Vector

三者的異同:ArrayList、LinkedList、Vector?

相同點:三個類都實現了List接口;存儲數據特點相同,有序,可重複

不同點:

​ ArrayList:作爲List接口的主要實現類,基本都用他,線程不安全,執行效率高,查詢快;底層使用的是Object[ ] elementData數組儲存數據

​ LikedList:對於頻繁的插入和刪除操作,使用LinkedList比ArrayList效率高,底層使用的是雙向鏈表儲存

​ Vector:List接口的古老實現類,很少用,JDK 1.0就有了,其他的都是1.2出現的,包括List,線程安全,執行效率低;底層是使用Object[ ] elementData儲存數據

ArrayList源碼分析(java.util包下):

JDK7:

​ JDK7在造對象的時候就給把底層的數組進行了初始化

ArrayList arraylist=new ArrayList();

1566870572500

1566870822848

JDK8:並沒有給原始數組初始化,節省內存空間,這樣的方式更好,在我們調用add方法的時候,我們的數組纔會被創建好

1566871345927

1566871300000

總結:

1566871955045

LinkedList源碼分析

​ 是一個雙向鏈表,


import java.util.LinkedList;

public class LinkedListTest<E> {
    int size;
    transient MyNode first;
    transient MyNode last;

    private static class MyNode<E>{
        private E element;
        private MyNode prev;
        private MyNode next;
        public MyNode(MyNode prev, E ele, MyNode next){
            this.element=ele;
            this.prev=prev;
            this.next=next;
        }
    }
//添加元素的方法,裏面有一個拼接的方法一個Node分爲三部分:【prev】【元素】【next】
    public void add(E ele){
        appendLast(ele);
    }
    //定義l節點爲last,
    public void appendLast(E ele){
        MyNode<E> l=last;
        MyNode newNode=new MyNode(l,ele,null);
        //last節點爲新節點
        last=newNode;
        //判斷新節點的【prev】是否爲null,是則表示爲該新節點爲【null】【ele】【null】
        //表示新結點爲first
        //否則,表示不是首節點,則把last的【next】指向新結點
        if(l==null){
            first=newNode;
        }else {
            l.next=newNode;
        }
        size++;
    }

    public void remove(E obj){
        //刪除元素
        //從頭開始遍歷,一直遍歷到結尾,只要沒到結尾就繼續遍歷
        for (MyNode pos=first;pos!=null;pos=pos.next){
            //判斷,當前元素pos是不是想要刪除的元素,是的就進行unlink方法,只要找到了就break
            if (pos.element.equals(obj)){
                unlink(pos);
                break;
            }
        }
    }
    //這裏就是刪除元素的方法
    private void unlink(MyNode<E> pos){
        //首先定義當前pos元素【prev】【ele】【next】
        E ele=pos.element;
        MyNode<E> prev=pos.prev;
        MyNode<E> next=pos.next;
        //判斷當前元素的【prev】是不是空,如果是空,那就表示是first,爲第一個節點
        //那就直接把第一個刪除,然後把pos後面的節點MyNode<E> next=pos.next 賦值給first
        //並把當前元素pos的【next】變成null,就不會指向後面的結點了,就斷開連接了
        if (prev==null){
            first=next;
            pos.next=null;
        }else {
            prev.next=next;
            pos.prev=null;
        }
        //判斷當前元素是不是最後一個,如果是就刪除最後一個元素,即讓前一個元素的變成爲最後一個last結點
        //否則把下一個元素的【prev】指向prev結點
        if (next==null){
            last=prev;
            pos.prev=null;
        }else {
            next.prev=prev;
            pos.next=null;
        }
        pos.element=null;
        size--;
    }
}

Set集合

是接口,存儲無序不重複的數據,Set接口繼承了Collection接口,同時沒有添加新的方法,所以在使用上與List接口的實現類使用方式一致。都是有增加元素的add方法和獲取元素個數的size方法

要求:
向set中添加數據,其所在類一定要重寫hashCode()和equals()方法;
重寫的hashCode()和equals()儘可能地保持一致:即相同對象必須擁有相同散列碼(相同對象要有一樣的哈希值)

具有三個實現類:

HashSet:作爲set接口的主要實現類,線程不安全:可以存儲null值

LinkedHashSet:是Hashset的子類,在Hashset基礎之上,添加了指針,遍歷其內部子類的時候,可以按照添加的順序遍歷。

TreeSet:使用紅黑樹存儲,要求放在TreeSet中的數據必須是同類型,可以按照添加對象的知道屬性進行排序

無序不可重複的理解:

1.無序性:解釋HashSet集合如何存放元素:

​ 無序性:不等於隨機性。存儲的數據在數組中並非按照數組索引的順序進行添加。而是根據數據的hash值決定的。

​ 當我們給HashSet中存放元素的時候,這時並不是直接把這個元素就存放到HashSet內部維護的數組中。

​ 而是先根據當前要存放的那個元素,再結合一種算法(這個方法就是Object類中的hashCode方法),算出當前這個元素應該在數組中存儲的位置。

​ 在存放數據的時候,如果計算出來的位置上已經有元素,這時還會去調用當前正要存放的這個元素的equals方法,把已經在計算出位置上的那個元素一起進行比較,如果equals方法返回的true,就丟棄當前正要存放的元素。如果equals方法返會的false,當前這個對象還要存儲。

2.不可重複性:HashSet集合是如何保證元素不重複

​ 不可重複性:表示在hashset中的元素 是不可重複的

當給hashset中存放元素的時候會先調用對象的hashCode方法,計算哈希值,根據哈希值來決定當前對象在集合中的存儲位置。

​ 在存儲的時候,如果遇到了哈希值相同的元素,這時集合的底層還會去調用當前對象的equals方法,判斷當前正要存放的對象和

​ 位置上已經存在的對象是否是同一個對象,equals方法返回的true,就認爲相同對象,不保存,如果equals方法返回的false,當前對象已經會被保存

1566963564305

計算哈希值得時候減少衝突

1566964307805

1566964075136

鏈表與數組的區別:

  1. 對於在內存中數據的存放順序及位置:

    數組中元素是按順序存放的,那麼在內存中也是按順序存放的,但是鏈表中元素存放的位置與內存中存放的順序及位置不一致;

    2.對於擴容的速度:

​ 鏈表的速度要快於數組,數據的擴容需要在內存在新申請一片內存空間,而鏈表直接擴就行

Map接口

存儲雙列數據:存儲key--value鍵值對的數據

一、實現類

HashMap:主要實現類;線程不安全,效率高,可以存儲null的key和value,key爲null可以使用方法,不會報空指針異常
LinkedHashMap---HashMap的子類;保證在遍歷map元素時,可以按照添加的順序實現遍歷。

​ 原因:在原有的hashMap底層結構基礎上,添加一對指針,指向前一個和後一個元素。

​ 對於頻繁的遍歷操作, 此類執行效率高於HashMap

TreeMap:可以按照添加的key-value進行排序,實現遍歷,按照key進行排序

​ 底層使用紅黑樹進行排序

Hashtable----是古老實現類;線程安全,效率低,不能存儲null的key和value,key爲null可以使用方法,會報空指針異常
properties---Hashtable的子類,常用來處理配置文件,key和value嗾使String類型
線程安全

1566965278032

面試題:

1.(高頻)HashMap底層實現原理

2.HashMap和Hashtable的異同

二、MAP結構的理解:

​ Map中 的key:無序的、不可重複,使用set存儲所有的key,

​ 要求:key所在的類要重寫equals()和hashCode()

​ Map中的value:無序的、可重複的,使用Collection存儲所有的value

​ 要求:value所在的類要重寫equals()方法

​ 一個鍵值對:key-value構成了一個Entry,key、value就是entry的屬性

​ Map中的entry:無序的,不可重複的,使用set存儲所有的entry

三、HashMap的底層原理

哈希衝突:

解決方法1:再哈希法===再次計算哈希值,直到每一個元素都有唯一的索引(位置)爲止

解決方法2:鏈地址法===使用鏈表

JDK7

1567015171057

import java.util.HashMap;

public class HashMapTest <K,V>{

    private Entry<K,V>[]table;
    private static final Integer INITCAPACITY=8;
    private int size;
    public HashMapTest(){
        table=new Entry[INITCAPACITY];
    }
    private int size(){
        return size;
    }
    private V get(Object key){
        int hash=key.hashCode();
        int i=hash%table.length;
        for (Entry<K,V> entry=table[i];entry!=null;entry=entry.next){
            if (entry.k.equals(key)){
                return entry.v;
            }
        }
        return null;
    }
    private V put(K key,V value){

        int hash=key.hashCode();
        int i=hash%table.length;
        for (Entry<K,V> entry=table[i];entry!=null;entry=entry.next){
            if (entry.k.equals(key)){
                V oldvalue=entry.v;
                entry.v=value;
                return oldvalue;
            }
        }
        addEntry(key, value, i);
        return null;
    }

    private void addEntry(K key, V value, int i) {
        Entry<K,V> entry=new Entry<K,V>(key,value,table[i]);
        table[i]=entry;
        size++;
    }

    class Entry<K,V>{
        private K k;
        private V v;
        private Entry<K,V>next;

        public Entry() {
        }

        public Entry(K k, V v, Entry<K, V> next) {
            this.k = k;
            this.v = v;
            this.next = next;
        }

        public K getK() {
            return k;
        }

        public V getV() {
            return v;
        }

    }

    public static void main(String[] args) {
        HashMapTest<Integer ,String>hashMapTest=new HashMapTest<Integer, String>();
        for(int i=0;i<10;i++){
            hashMapTest.put(i,"結束"+i);
            System.out.println(hashMapTest.get(i));
        }

    }
}

1567015212088

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章