1. 程式人生 > >java集合(List,Set,Map)詳細總結

java集合(List,Set,Map)詳細總結

麻煩 array map接口 安全 content 想要 鍵值 more san

集合的由來:

  數組是長度是固定的,當添加的元素超過數組的長度時需要對數組重新定義,太麻煩了,java內部給我們提供了集合類,能存儲任意對象,長度是可以改變的,隨著元素的增加而增加,隨著元素的減少而減少。

數組與集合的區別:          

  數組既可以存儲引用數組類型,又可以存儲引用數據類型,基本數據類型存儲的是值,引用數據類型存儲的是地值。     集合只能存儲引用數據類型(對象),集合中也可以存儲基本數據類型,但是在存儲的時候會自動裝箱變成對象。

集合的結構:

  Collection
    ├List
    │├LinkedList
    │├ArrayList
    │└Vector
    │ └Stack
    └Set
     Map
    ├Hashtable
    ├HashMap
    └WeakHashMap


  技術分享圖片

Collection接口介紹:

  Collection是最基本的集合接口,一個Collection代表一組Object,即Collection的元素(Elements)。一些Collection允許相同的元素而另一些不行。一些能排序而另一些不行。Java SDK不提供直接繼承自Collection的類,Java SDK提供的類都是繼承自Collection的“子接口”如List和Set。
所有實現Collection接口的類都必須提供兩個標準的構造函數:無參數的構造函數用於創建一個空的Collection,有一個Collection參數的構造函數用於創建一個新的Collection,這個新的Collection與傳入的Collection有相同的元素。後一個構造函數允許用戶復制一個Collection。
如何遍歷Collection中的每一個元素?不論Collection的實際類型如何,它都支持一個iterator()的方法,該方法返回一個叠代子,使用該叠代子即可逐一訪問Collection中每一個元素。典型的用法如下:

1Iterator  it  =  collection.iterator();  //  獲得一個叠代子
2 while(it.hasNext())  {
3      Object  obj  =  it.next();  //  得到下一個元素
4 }

叠代器原理:

叠代器是對集合進行遍歷,而每一個集合內部的存儲結構都是不同的,所以每一個集合存和取都是不一樣,那麽就需要在每一個類中定義hasNext()和next()方法,這樣做是可以的,但是會讓整個集合體系過於臃腫,叠代器是將這樣的方法向上抽取出接口,然後在每個類的內部,定義自己叠代方式,這樣做的好處有二,第一規定了整個集合體系的遍歷方式都是hasNext()和next()方法,第二,代碼有底層內部實現,使用者不用管怎麽實現的,會用即可

List介紹 

  List是有序的Collection,使用此接口能夠精確的控制每個元素插入的位置。用戶能夠使用索引(元素在List中的位置,類似於數組下標)來訪問List中的元素,這類似於Java的數組。
和下面要提到的Set不同,List允許有相同的元素。
除了具有Collection接口必備的iterator()方法外,List還提供一個listIterator()方法,返回一個ListIterator接口,和標準的Iterator接口相比,ListIterator多了一些add()之類的方法,允許添加,刪除,設定元素,還能向前或向後遍歷。
實現List接口的常用類有LinkedList,ArrayList,Vector和Stack。

 1         //List數據遍歷,以及基本操作
 2         List list =new ArrayList();
 3         list.add("a");
 4         list.add("b");
 5         list.add("c");
 6         list.add("d");
 7         list.set(2, "a");    //根據索引,往2索引Set一個值
 8         System.out.println(list.get(2));    //根據索引獲取結果
 9         Object remove = list.remove(100); //刪除索引,將刪除的元素返回
10         for (int i = 0; i < list.size(); i++) {
11             System.out.println(list.get(i)); //獲取索引中的值
12         }
13     }

LinkedList介紹


  LinkedList實現了List接口,允許null元素。此外LinkedList提供額外的get,remove,insert方法在LinkedList的首部或尾部。這些操作使LinkedList可 被用作堆棧(stack),隊列(queue)或雙向隊列(deque)。        

  註意LinkedList沒有同步方法。如果多個線程同時訪問一個List,則必須自己實現訪問同步。一種解決方法是在創建List時構造一個同步的List:
  List list = Collections.synchronizedList(new LinkedList(...));

 1 //LinkedList的基本使用
 2 public static void main(String[] args) {
 3         LinkedList list = new LinkedList();
 4         list.addFirst("a");
 5         list.addFirst("b");
 6         list.addFirst("c");        //添加數據先進先出的模式
 7         list.addFirst("d");
 8         list.addLast("e");        //往尾部添加數據
 9 //        System.out.println(list);    //查看全部數據
10         System.out.println(list.getFirst());    //查看頭部數據
11         System.out.println(list.getLast());        //查看尾部數據
12         System.out.println(list.removeFirst());    //刪除頭部添加的數據
13         System.out.println(list.removeLast());    //刪除尾部添加的數據
14         System.out.println(list.get(1));
15         System.out.println(list);

ArrayList介紹:


  ArrayList實現了可變大小的數組。
它允許所有元素,包括null。ArrayList沒有同步。
size,isEmpty,get,set方法運行時間為常數。但是add方法開銷為分攤的常數,添加n個元素需要O(n)的時間。其他的方法運行時間為線性。    
每個ArrayList實例都有一個容量(Capacity),即用於存儲元素的數組的大小。這個容量可隨著不斷添加新元素而自動增加,但是增長算法並沒有定義。 當需要插入大量元素時,在插入前可以調用ensureCapacity方法來增加ArrayList的容量以提高插入效率。
和LinkedList一樣,ArrayList也是非同步的(unsynchronized)。

 1 public static void main(String[] args) {
 2             ArrayList list=new ArrayList();
 3             list.add(new Student("jy",17));    //數據添加
 4             list.add(new Student("jy",17));
 5             list.add(new Student("jj",171));
 6             list.add(new Student("jj",171));
 7             //list.add(5, new Student("jj",171));// 在集合的某一個位置添加對象
 8             // list.addAll(2, list2);    // 在集合的某一個位置添加一個集合
 9             // list.remove(2);    //根據索引刪除
10             //list.set(2, new Student("jj",171));    //修改
11             //Object[] array = list.toArray();    //轉數組
12             //使用叠代器
13             Iterator it=list.iterator();
14             it=list.iterator();
15             //遍歷集合
16             while (it.hasNext()) {
17                 Student type = (Student) it.next();
18                 System.out.println("name:"+ type.getName() + "---> Age:" + type.getAge());
19         }
20     }    

Vector介紹:

  Vector 是矢量隊列,它是JDK1.0版本添加的類。繼承於AbstractList,實現了List, RandomAccess, Cloneable這些接口。
Vector 繼承了AbstractList,實現了List;所以,它是一個隊列,支持相關的添加、刪除、修改、遍歷等功能
Vector 實現了RandmoAccess接口,即提供了隨機訪問功能。RandmoAccess是java中用來被List實現,為List提供快速訪問功能的。在Vector中,我們即可以通過元素的序號快速獲取元素對象;這就是快速隨機訪問。
Vector 實現了Cloneable接口,即實現clone()函數。它能被克隆。
和ArrayList不同,Vector中的操作是線程安全的。(Vector功能都不及ArrayList與LinkedList好用,了解就好)

 1     public static void main(String[] args) {
 2         Vector v = new Vector();
 3         v.addElement("1");
 4         v.addElement("11");
 5         v.addElement("111");
 6         v.addElement("1111");
 7         v.addElement("11111");
 8         Enumeration en =v.elements();            //獲取枚舉,遍歷
 9         while(en.hasMoreElements()){            //判斷集合中是否有元素
10             System.out.println(en.nextElement());    //獲取集合中的元素
11         }
12     }

總結:

ArrayList:

  底層數據結構是數組,查詢快,增刪慢。

  線程不安全,效率高。

Vector:

  底層數據結構是數組,查詢快,增刪慢。

  線程安全,效率低。

  Vector相對ArrayList查詢慢(線程安全的)

  Vector相對LinkedList增刪慢(數組結構)

LinkedList:

  底層數據結構是鏈表,查詢慢,增刪快。

  線程不安全,效率高。

Vector和ArrayList的區別:

  Vector是線程安全的,效率低

  ArrayList是線程不安全的,效率高

  共同點:都是數組實現的

ArrayList和LinkedList的區別:

  ArrayList底層是數組結果,查詢和修改快

  LinkedList底層是鏈表結構的,增和刪比較快,查詢和修改比較慢

List有三個兒子,我們到底使用誰呢?

  查詢多用ArrayList

  增刪多用LinkedList

  如果都多ArrayList


Set介紹:

  父接口 Collection

  2.特點 唯一 無序(插入順序跟遍歷順序不一致,沒下標)

    唯一:Set集合中不允許出現重復的元素,如果向Set集合中存儲重復的元素是無效的,但不會報錯

    無序:Set集合不會維護集合中元素的插入順序,即不存在下標或索引

  3.Set接口中的功能方法 (Set接口中沒有自有方法,全部繼承自Collection接口)

  4.凡是帶有下標的方法都不支持

HashSet介紹:

  我們使用Set集合都是需要去掉重復元素的, 如果在存儲的時候逐個equals()比較, 效率較低,哈希算法提高了去重復的效率, 降低了使用equals()方法的次數

當HashSet調用add()方法存儲對象的時候, 先調用對象的hashCode()方法得到一個哈希值, 然後在集合中查找是否有哈希值相同的對象

如果沒有哈希值相同的對象就直接存入集合

如果有哈希值相同的對象, 就和哈希值相同的對象逐個進行equals()比較,比較結果為false就存入, true則不存

 1     HashSet<String> hs = new HashSet<String>();    //創建HashSet對象
 2         boolean b1 = hs.add("a");
 3         boolean b2 = hs.add("a");                    //當向set集合中存儲重復元素的時候返回為false
 4         hs.add("a");
 5         hs.add("b");
 6         hs.add("c");        
 7         hs.add("d");                                //HashSet的繼承體系中有重寫toString的方法
 8         System.out.println(hs);
 9         System.out.println(b1);
10         System.out.println(b2);
11         for (String string : hs) {            //只要用叠代器的,就可以使用增強for循環遍歷
12             System.out.println(string);
13         }
14     }

LinkedHashSet介紹:

  底層是鏈表實現的,時Set集合唯一一個能保證怎麽存就怎麽取的集合對象

因為HashSet的子類,所以也是保證元素的唯一的,與HashSet的原理一樣

1 public static void main(String[] args) {
2         LinkedHashSet<String> lhs = new LinkedHashSet<String>();
3         lhs.add("a");
4         lhs.add("aa");
5         lhs.add("aaa");
6         lhs.add("aaa");
7         lhs.add("a");
8         System.out.println(lhs);
9     }

TreeSet介紹:

  TreeSet存儲Integer類型的元素並遍歷

  當compareTo方法返回()的時候集合中只有一個元素

  當compareTo方法返回正數的時候集合回怎麽存就怎麽取

  當compareTo方法返回符數的時候集合回倒序存儲

 1 public static void main(String[] args) {
 2         //按照字符串長度進行排序
 3         TreeSet<String> ts = new TreeSet<String>(new ComareByLen());
 4         ts.add("aaa");                    //Comparator c = new Comparator(); 
 5         ts.add("aa");
 6         ts.add("aaaa");
 7         ts.add("aaaaa");
 8         System.out.println(ts);
 9     }
10 class ComareByLen implements Comparator<String>{
11 
12         @Override
13         public int compare(String o1, String o2) {
14             int num = o1.length() - o2.length();    //定義一個比較器
15             return num == 0 ? o1.compareTo(o2):num;
16         }
17         
18     }

總結:

Set:存取無序,無所索引,不可以重復

HashSet:

    底層是哈希算法實現

   LinkedHashset:

      底層是鏈表實現的,但是也是可以保證元素唯一,和Hashset原理一樣

   TreeSet:

      底層是二叉樹算法實現

  一般在開發中的時候不需要對存儲元素進行排序,所以開發的時候大多HashSet,HaShSet的效率比較高

   TreeSet在面試的時候問的比較多,問你集中排序方式,和集中排序方式的區別

並發修改異常:

  1.在遍歷一個集合時,如果需要刪除一個數據,那麽會容易出現並發修改異常

  2.誰遍歷,就讓誰刪除(例如在遍歷Set的時候不允許刪除Set(叠代器是單獨一個線程,涉及到數據同步的問題),可以通過叠代器的remove方法來解決)

  3.就必須使用原始的叠代器代碼

Map介紹:

  |--Hashtable:底層是哈希表數據結構,是線程同步的。不可以存儲null鍵,null值。

   |--HashMap:底層是哈希表數據結構,是線程不同步的。可以存儲null鍵,null值。替代了Hashtable.

   |--TreeMap:底層是二叉樹結構,可以對map集合中的鍵進行指定順序的排序。

Map集合存儲和Collection有著很大不同:

  Collection一次存一個元素;Map一次存一對元素。

  Collection是單列集合;Map是雙列集合。

  Map中的存儲的一對元素:一個是鍵,一個是值,鍵與值之間有對應(映射)關系。

  特點:要保證map集合中鍵的唯一性。

1,添加。

put(key,value):當存儲的鍵相同時,新的值會替換老的值,並將老值返回。如果鍵沒有重復,返回null。

void putAll(Map);

2,刪除。

void clear():清空

value remove(key) :刪除指定鍵。

3,判斷。

boolean isEmpty():

boolean containsKey(key):是否包含key

boolean containsValue(value) :是否包含value

4,取出。

int size():返回長度

value get(key) :通過指定鍵獲取對應的值。如果返回null,可以判斷該鍵不存在。當然有特殊情況,就是在hashmap集合中,是可以存儲null鍵null值的。

Collection values():獲取map集合中的所有的值。

5,想要獲取map中的所有元素:

原理:map中是沒有叠代器的,collection具備叠代器,只要將map集合轉成Set集合,可以使用叠代器了。之所以轉成set,是因為map集合具備著鍵的唯一性,其實set集合就來自於map,set集合底層其實用的就是map的方法。

map集合轉成set的方法:

Set keySet();

Set entrySet();//取的是鍵和值的映射關系。

Entry就是Map接口中的內部接口;

為什麽要定義在map內部呢?entry是訪問鍵值關系的入口,是map的入口,訪問的是map中的鍵值對。

---------------------------------------------------------

取出map集合中所有元素的方式一:keySet()方法。

  可以將map集合中的鍵都取出存放到set集合中。對set集合進行叠代。叠代完成,再通過get方法對獲取到的鍵進行值的獲取。

Set keySet = map.keySet();

Iterator it = keySet.iterator();

while(it.hasNext()) {

Object key = it.next();

Object value = map.get(key);

System.out.println(key+":"+value);

}

--------------------------------------------------------

取出map集合中所有元素的方式二:entrySet()方法。

Set entrySet = map.entrySet();

Iterator it = entrySet.iterator();

while(it.hasNext()) {

Map.Entry me = (Map.Entry)it.next();

System.out.println(me.getKey()+"::::"+me.getValue());

}

--------------------------------------------------------

使用集合的技巧:

  看到Array就是數組結構,有角標,查詢速度很快。

  看到link就是鏈表結構:增刪速度快,而且有特有方法。addFirst; addLast; removeFirst(); removeLast(); getFirst();getLast();

  看到hash就是哈希表,就要想要哈希值,就要想到唯一性,就要想到存入到該結構的中的元素必須覆蓋hashCode,equals方法。

  看到tree就是二叉樹,就要想到排序,就想要用到比較。

比較的兩種方式:

一個是Comparable:覆蓋compareTo方法;

一個是Comparator:覆蓋compare方法。

  LinkedHashSet,LinkedHashMap:這兩個集合可以保證哈希表有存入順序和取出順序一致,保證哈希表有序。

集合什麽時候用?

  當存儲的是一個元素時,就用Collection。當存儲對象之間存在著映射關系時,就使用Map集合。

  

保證唯一,就用Set。不保證唯一,就用List。

------------------------------------------------------------------------------------------------

Collections:它的出現給集合操作提供了更多的功能。這個類不需要創建對象,內部提供的都是靜態方法。

靜態方法:

Collections.sort(list);//list集合進行元素的自然順序排序。

Collections.sort(list,new ComparatorByLen());//按指定的比較器方法排序。

class ComparatorByLen implements Comparator<String>{

public int compare(String s1,String s2){

int temp = s1.length()-s2.length();

return temp==0?s1.compareTo(s2):temp;

}

}

Collections.max(list); //返回list中字典順序最大的元素。

int index = Collections.binarySearch(list,"zz");//二分查找,返回角標。

Collections.reverseOrder();//逆向反轉排序。

Collections.shuffle(list);//隨機對list中的元素進行位置的置換。

將非同步集合轉成同步集合的方法:Collections中的 XXX synchronizedXXX(XXX);

  List synchronizedList(list);

  Map synchronizedMap(map);

原理:定義一個類,將集合所有的方法加同一把鎖後返回。

Collection 和 Collections的區別:

  Collections是個java.util下的類,是針對集合類的一個工具類,提供一系列靜態方法,實現對集合的查找、排序、替換、線程安全化(將非同步的集合轉換成同步的)等操作。

  Collection是個java.util下的接口,它是各種集合結構的父接口,繼承於它的接口主要有Set和List,提供了關於集合的一些操作,如插入、刪除、判斷一個元素是否其成員、遍歷等。

-------------------------------------------------------

Arrays:

  用於操作數組對象的工具類,裏面都是靜態方法。

asList方法將數組轉換成list集合。

  String[] arr = {"abc","kk","qq"};

  List<String> list = Arrays.asList(arr);//將arr數組轉成list集合。

將數組轉換成集合,有什麽好處呢?用aslist方法,將數組變成集合;

  可以通過list集合中的方法來操作數組中的元素:isEmpty()、contains、indexOf、set;

註意(局限性):數組是固定長度,不可以使用集合對象增加或者刪除等,會改變數組長度的功能方法。比如add、remove、clear。(會報不支持操作異常UnsupportedOperationException);

  如果數組中存儲的引用數據類型,直接作為集合的元素可以直接用集合方法操作。

如果數組中存儲的是基本數據類型,asList會將數組實體作為集合元素存在。

集合變數組:用的是Collection接口中的方法:toArray();

  如果給toArray傳遞的指定類型的數據長度小於了集合的size,那麽toArray方法,會自定再創建一個該類型的數據,長度為集合的size。

如果傳遞的指定的類型的數組的長度大於了集合的size,那麽toArray方法,就不會創建新數組,直接使用該數組即可,並將集合中的元素存儲到數組中,其他為存儲元素的位置默認值null。

所以,在傳遞指定類型數組時,最好的方式就是指定的長度和size相等的數組。

將集合變成數組後有什麽好處?

  限定了對集合中的元素進行增刪操作,只要獲取這些元素即可。

java集合(List,Set,Map)詳細總結