一.集合就像一種容器,能夠動態的把多個對象的引用html
放入到容器中,存儲多個數據 。java
集合數組都是對多個數據進行存儲操做的結構,簡稱java容器面試
2、集合框架、算法
collection接口:單列集合,用來存儲一個一個對象api
list接口:存儲有序可重複的數據數組
實現類:ArrayList LinkedList 安全
set接口:存儲無序,不可重複的數據oracle
實現類:HashSetapp
map接口:雙列集合,用來存儲一對一對的數據框架
實現類:HashMap
3、collection(爲何不用collection? 由於即有序又無序,便可重複,又不可重複,找不到這樣的容器,因此纔會用List和Set)
Collection coll=new ArrayList(); coll.add("aa");
Collection coll=new ArrayList(); Collection coll1=new ArrayList(); coll1.add("bb"); coll.addAll(coll1);
Collection coll=new ArrayList(); coll.add("aa"); coll.clear();
Collection coll=new ArrayList(); coll.add("aa"); coll.clear(); coll.isEmpty();
例如:
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()方法。 } }
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
coll.remove(new Person("wwuu",123)); System.out.println(coll);//因爲上述的方法中已經對Person這個類進行了equals()方法的重寫,故而這裏是能夠對new Person("wwuu",123)這個元素進行刪除的,若是不重寫equals方法則刪除不了
coll.removeAll(coll1); System.out.println(coll1); System.out.println(coll);
Collection coll2=new ArrayList(); coll2.add(123); coll2.add(new String ("huhu")); coll2.add(new String("bb")); coll.retainAll(coll2); System.out.println(coll);
Collection coll3= Arrays.asList(123,"huhu","bb"); System.out.println(coll2.equals(coll3));
System.out.println(coll3.hashCode());
Object[] objects = coll3.toArray(); for (Object o: objects) { System.out.println(o); }
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個參數
Iterator iterator=coll2.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); }
foreach(Object obj: coll2){ System.out.println(obj); }
他是一個接口,一般用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儲存數據
JDK7:
JDK7在造對象的時候就給把底層的數組進行了初始化
ArrayList arraylist=new ArrayList();
JDK8:並無給原始數組初始化,節省內存空間,這樣的方式更好,在咱們調用add方法的時候,咱們的數組纔會被建立好
總結:
是一個雙向鏈表,
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接口繼承了Collection接口,同時沒有添加新的方法,因此在使用上與List接口的實現類使用方式一致。都是有增長元素的add方法和獲取元素個數的size方法
具備三個實現類:
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,當前對象已經會被保存
計算哈希值得時候減小衝突
鏈表與數組的區別:
對於在內存中數據的存放順序及位置:
數組中元素是按順序存放的,那麼在內存中也是按順序存放的,可是鏈表中元素存放的位置與內存中存放的順序及位置不一致;
2.對於擴容的速度:
鏈表的速度要快於數組,數據的擴容須要在內存在新申請一片內存空間,而鏈表直接擴就行
存儲雙列數據:存儲key--value鍵值對的數據
緣由:在原有的hashMap底層結構基礎上,添加一對指針,指向前一個和後一個元素。
對於頻繁的遍歷操做, 此類執行效率高於HashMap
底層使用紅黑樹進行排序
1.(高頻)HashMap底層實現原理
2.HashMap和Hashtable的異同
Map中 的key:無序的、不可重複,使用set存儲全部的key,
要求:key所在的類要重寫equals()和hashCode()
Map中的value:無序的、可重複的,使用Collection存儲全部的value
要求:value所在的類要重寫equals()方法
一個鍵值對:key-value構成了一個Entry,key、value就是entry的屬性
Map中的entry:無序的,不可重複的,使用set存儲全部的entry
哈希衝突:
解決方法1:再哈希法===再次計算哈希值,直到每個元素都有惟一的索引(位置)爲止
解決方法2:鏈地址法===使用鏈表
JDK7
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)); } } }