java基礎_09_集合

集合

用於存儲對象(對象的引用地址)

集合的結構圖

委屈 

 

Collection

|--List:元素是有序的,按存入次序依次存放,元素可以重複。因爲該集合體繫有索引。

|--ArrayList  : 底層的數據結構使用的是數組結構。特點:查詢速度很快,但是增刪稍慢。線程不同步。

|--LinkedList  : 底層使用的是鏈表數據結構。特點:增刪速度很快,但查詢稍慢

|--vector  : 底層是數組數據結構。 線程同步。 被ArrayList替代了。

 

|--Set :元素是無序的,按指定排序方法存放,元素不可以重複

|--HashSet : 底層數據結構是哈希表

|--TreeSet  : 底層數據結構是二叉樹,可以對Set集合中的元素進行排序。

     保證元素唯一性的依據:compareTo 方法 return 0;

 

        Set 集合的功能和Collection 是一致的,其實,Set底層就是使用了Map集合。

 

Map 

|--Hashtable : 底層是哈希表數據結構,不可以存入null鍵null值。該集合是線程同步的。JDK1.0  效率低

|--HashMap: 底層是哈希表數據結構,允許使用null值和null鍵,該集合是不同步的。將hashtable替代,jdk1.2 效率高

|--TreeMap : 底層是二叉樹數據結構。線程不同步。可以用於給Map集合中的鍵進行排序。

 

Collection 接口

     集合的根接口。

     1,  add方法參數類型是Objext 以便於接收任意類型對象

     2,集合中存儲的都是對象的引用(地址)

     3,集合轉數組。

         例:String s  =  new String[集合.size()] ;

  爲什麼要將集合變數組?

  爲了限定對元素的操作,(不需要進行增刪了,只能查就行)

  注:Arrays 類中有大量操作數組的靜態方法。

 

Collections 類

     此類完全由在 collection 上進行操作或返回 collection 的靜態方法組成.

     常用方法:

       sort(List<T> list)       根據元素的自然順序 對指定列表按升序進行排

   swap(List<?> list, int i, int j)在指定列表的指定位置處交換元素

  shuffle(List<?> list)對集合元素隨機排序

   reverse(List<?> list)反轉指定列表中元素的順序

   reverseOrder()  返回一個比較器,它強行逆轉實現Comparable 接口的對collection 自然順序

   reverseOrder(Comparator<T> cmp)返回一個比較器,它強行逆轉指定比較器的順序

  例 :

   TreeSet<String> ts = new TreeSet<String>(Collections.reverseOrder(new Mycomparator())); 

   class Mycomparator implements Comparator<String>

  {

     public int compare(String s1,String s2)

     {

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

        if(num>0)

             return 1;

         if(num<0)

              return -1;

         return s1.compareTo(s2);

      }

   }

 

下面是一些常用的集合:

List 集合

特點:所存入的元素是按存入順序存放的,元素可以重複。

List集合特有的迭代器 : ListIterator  是Iterator的子接口。

如果想要操作如添加,修改等,就需要使用其子接口 ListIterator

 

如何將數組轉變成集合呢?

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

 

數組轉集合有什麼好處?

可以使用集合的思想和方法來操作數組中的元素。

 

注意:將數組變成集合,不可以使用集合的增刪方法。

因爲數組的長度是固定的。

如果增刪會發生 UnsupportedOperationException 異常。

 

注意: 如果數組中的元素都是對象,那麼變成集合時,數組中的元素就直接轉成集合中的素。

            如果數組中的元素都是基本數據類型,那麼會將 該數組 作爲集合的元素存在。

例:

String s [] ={"a","bbbd","kcd","z"};  

List<String> list = Arrays.asList(s);

int a [] = {2,4,5};

List<int []> li = Arrays.asList(a);  //2,4,5表示的是基本數據類型

Integer num[] = {2,4,5};

List<Integer> li2 = Arrays.asList(num); //2,4,5會自動裝箱,本身就是對象了

 

下面兩個常用的List集合,如果想支持隨機訪問,而不必在首尾的任何位置插入或刪除元素,那麼使用ArrayList 集合,如果要對集合進行頻繁的添加和刪除操作,對集合的首尾操作多,那麼使用LinkedList 集合更好。它提供了很多處理元素的方法。

    1,ArrayList 

       底層的數據結構使用的是數組結構。

        特點:查詢速度很快,但是增刪稍慢。線程不同步。

        該類封裝了一個動態再分配的Object[]數組,每個ArrayList對象有一個capacity.這個capacity表示存儲列表中元素的數組的容量,在向集合中加入元素時,capacity在自動增加。

       注意:contains(Object o) 方法,內部自動調用equals方法來比較的。

          (o==null ? e==null : o.equals(e)) 

 例:

//去重複元素

 public static ArrayList method(ArrayList al)
    	{
    		List newal = new ArrayList();
    
    		Iterator it = al.iterator();
    
    		while(it.hasNext())
    		{
    		        Object obj = it.next();
    			if(!newal.contains(obj))
    				newal.add(obj);
    		}
    		return newal;
    	}

 

2,LinkedList 

        底層使用的鏈表數據結構。特點:增刪速度很快,但查詢稍慢   

   該類添加了一些處理列表兩端元素的方法。實現所有可選的列表操作,並且允許所有元素

  (包括null)。除了實現 List 接口外,LinkedList 類還爲在列表的開頭及結尾 getremove 和 insert 元素提供了統一的命名方法

3,Vector

        底層是數組數據結構。 線程同步。 被ArrayList替代了。

    枚舉就是Vector特有的取出元素方式

    其實枚舉和迭代是一樣的,因爲枚舉的名稱以及方法的名稱都過長,所以被換代器取代了 

    使用方法:

 
 
	   

Vector v = new Vector();

v.add("java001");

v.add("java002");

Enumeration en = v.elements();

while(en.hasMoreElements())

{

System.out.println(en.nextElement());

}

 

4,Stack

   Stack 類表示後進先出(LIFO)的對象堆棧。它通過五個操作對類 Vector 進行了擴展 ,允許將向量視爲堆棧。它提供了通常的 push 和 pop 操作,以及取堆棧頂點的 peek 方法、測試堆棧是否爲空的 empty 方法、在堆棧中查找項並確定到堆棧頂距離的 search 方法.

 

Set 集合

特點:所存入的元素按指定排序方法存放元素(即不是按存入順序存放),不可以重複元素。

Set底層是使用了Map集合。

1,HasHSet 

   數據結構是哈希表,線程是非同步的

   保證元素唯一性的原理:

   判斷元素的hashCode值是否相同。如果相同,還會繼續判斷元素的equals方法,是爲true 如果不同,不會判斷equals

   一般使用HashSet 都須要覆蓋hashCode()、equals() 兩個方法

   例:

往HashSet 集合中存入自定義對象。

假設:姓名和年齡相同爲同一個人,是重複元素。

public int hashCode() //自動調用 ,複寫父類。調用這個纔有機會去調用equals方法

           {

               return  name.hashCode()+age*37;//只要返回的hashCode值唯一就行 

           }

           public boolean equals(Object obj) //複寫父類

          {

              if(!(obj instanceof Person)) 

                      return false;

              Person p = (Person)obj;

              return this.name.equals(p.name)  &&  this.age == p.age;

           }

   注意:對於判斷元素是否存在,以及刪除等操作,依賴的方法是元素的hashCode和equals方法

       記住:排序時,當主要條件相同時,一定要判斷一下次要條件。

 

 hashCode()作用:

 hashCode()值可以說成是對象在內存中計算出來的一個值,如果值等,說明對象是同一個對象,所以這裏程序員可以通過複寫hashCode()來判斷讓其那些是同一類型。爲了提高效率,讓其在查找集合中是否有相同對象的時候,把hashCode()值在內存中進行了分區存放的,這樣查找起來就效率提高了。正因爲這樣,所以在一個對象存入hash集合中的時候,就不要去更改對象中的值了,否則就會產生內存泄漏(就是內存浪費)。爲什麼呢?因爲更改了值後,導致hashCode的改變,導致存放的區域發生了變化,所以再去刪除這個對象的時候,這個對象已不在這個區域了,是無法刪除到這個對象的,刪除的是沒改之前的對象,而這個對象已沒用了。放在這裏就是一處內存泄漏。

 

2,TreeSet 

   底層數據結構是二叉樹。 

   特點:可以對Set集合中的元素進行排序。

   但必須指明排序要求。

   例:

TreeSet ts = new TreeSet(new MyCompare()); 

new MyCompare() 就是比較器

   保證元素唯一性的依據:compareTo 方法 return 0;

 

 排序方式:   兩種

 

TreeSet排序的第一種方式:

讓元素自身具備比較性。這種方式也稱爲元素的自然順序,或者叫做默認順序。

               使用方法:

1,該類實現Comparable接口

2,覆蓋compareTo方法

例 :

    class Student implements Comparable  // 1,實現Comparable接口 該接口強制讓學生具備比較性
    { 
      public int compareTo(Object obj)  // 2,覆蓋compareTo方法,是自動調用的
    	{
    		//按照學生的年齡進行排序
    		if(!(obj instanceof Student))
    			throw new RuntimeException("不是學生對象");
    
    		Student s = (Student)obj;
    		if(this.age>s.age)
    			return 1;
    		if(this.age==s.age)
    		{
    			return this.name.compareTo(s.name);  //字符串的比較功能
    		}
    		return -1;
    
    /*
    注意:如果想實現按怎麼進來的怎麼出去
    只須 compareTo方法 return -1;或 return 1; 即可。
    因爲二叉樹:存放的時候是大的放在右邊,小的放在左邊,
          默認輸出從小到大。
     -1 表示小 0 表示等 1表示大
    */
    }
    }

TreeSet的第二種排序方式:

           當元素自身不具備比較性時,或者具備的比較性不是所需要的。

           這時就需要讓集合自身具備比較性。

            使用方法:

           1,定義比較器,實現Comparator接口

           2,覆蓋compare方法

           3,將比較器對象作爲參數傳遞給TreeSet集合的構造函數。

           例:

                需求:現在要求按學生姓名排序。 

    class MyCompare implements Comparator		//1,定義比較器,實現Comparator接口
    {
    	public int compare(Object o1,Object o2)	//2,複寫compare方法
    	{
    		Student s1 = (Student)o1;
    		Student s2 = (Student)o2;
    
    		int num = s1.getName().compareTo(s2.getName());
    		if(num==0)
    		{
    			if(s1.getAge()>s2.getAge())
    				return 1;
    			if(s1.getAge()<s2.getAge())
    				return -1;
    			return 0;
    		}
    		return num;
    	}
    }

          注意:如果自身具有比較性,但又傳入了比較器,那麼以比較器爲主。

 

Map 集合

Map接口不是Collection接口的繼承。

和Set很像,其實,Set底層就是使用了Map集合。

 

什麼時候使用map集合呢?

當數據之間存在映射關係時,就可以使用map集合,因爲Map集合中存放就是映射關係。

 

Map集合的兩種取出元素方式:

Map集合的取出原理:將Map集合轉成Set集合,在通過迭代器取出。

 

一,Set<K>  keySet 

將Map中所有的鍵存入到Set集合,因爲Set具備迭代器。

所以可以用迭代方式取出所有的鍵,在根據get方法。獲取每一個鍵對應的值。

例: 

    Map<String,String> map = new HashMap<String,String>();
    
    Set<String> keySet = map.keySet(); //1,獲取Map集合的所有鍵,保存到Set集合

    Iterator<String> it1 = keySet.iterator();  以鍵值迭代
    while (it1.hasNext())
    {
       String skey = it1.next();
    	  String svalue = map.get(skey);   通過鍵值獲取對應的值。
    
    	  System.out.println("key:"+skey+"_____"+svalue);
    }

 

二,Set<Map.Entry<k,v>>  entrySet 

將Map集合中的映射關係存入到Set集合中,而這個關係的數據類型就是:Map.Entry然後在通過迭代器來取數據。

例:

    Map<String,String> map = new HashMap<String,String>();
    
    //將Map集合中的映射關係取出,存入到Set集合中
    Set<Map.Entry<String,String>> entrySet = map.entrySet();
    Iterator<Map.Entry<String,String>> it = entrySet.iterator();
    while (it.hasNext())
    {
      Map.Entry<String,String> me = it.next();//迭代器中返回的值的類型和泛型<>裏的類型一樣
    	 String key = me.getKey();
    	 String value = me.getValue();
    	 System.out.println(key+"..."+value);
    }

 

 1,HashMap 

   底層是哈希表數據結構,允許使用null值和null鍵,該集合是不同步的。將hashtable替代,jdk1.2 效率高 , 適合在集合中插入,刪除和定位元素。

   例:

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

   map.put("01","zhangsan1");

   map.put("01","zhangsan1");//如果出現添加相同的鍵,那麼後添加的值會覆蓋原有鍵對應值,並返回被覆蓋的值。

  

  判斷一個鍵是否存在?

  可以通過get方法的返回值來判斷一個鍵是否存在。通過返回null來判斷

  System.out.println( map.get("04") );//返回null

 

  獲取map集合中的 Collection 視圖。

  Collection<String> coll = map.values();

 

2,TreeMap 

   底層是二叉樹數據結構。線程不同步。可以用於給Map集合中的鍵進行排序。

   如果想按自然順序或自定義順序排序,使用該集合。

   例:

字符串“osjfosj0fwamfw0fimdsoja”獲取該字符串中的字母出現的次數。

希望打印結果:a(1)b(3)c(2)....

思路:通過結果可以看到,每一個都有對應的次數,說明字母和次數之間都有映射關係。

所以選擇Map集合,因爲輸出結果是有序的,所以使用TreeMap

步驟:

1,將字符串轉換成字符數組,因爲要對每一個字母進行操作。

2,定義一個map集合,因爲打印結果的字母有順序,所以使用TreeMap集合

3,遍歷字符數組

   將每一個字母作爲鍵去查map集合

   如果返回null ,將該字母和次數1存入到map集合

   如果返回不是null ,說明字母已存在,把對應的次數加1

4,遍歷map集合以指定形式打印。

     public static void charCount2(String str)
    	{
    		char chs[] = str.toCharArray();  //1,返回字符數組
    
    		//泛型裏放的是引用對象
    		TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>();
    		
    		int count = 0;
    		for(int i=0;i<chs.length;i++)
    		{
    			Integer value = tm.get(chs[i]);  //不存在就返回null
    			if(value!=null)
    				count = value;
    			count++;
    			tm.put(chs[i],count); //加入集合,如有就更新這對值
    			count = 0;
    		}
    				
    		Set<Map.Entry<Character,Integer>> entrySet = tm.entrySet();
    		Iterator<Map.Entry<Character,Integer>> it = entrySet.iterator();
    
    		while (it.hasNext())
    		{
    			Map.Entry<Character,Integer> me = it.next();
    			Character ch = me.getKey();
    			Integer value = me.getValue();
    			System.out.print(ch+"("+value+")");
    		}
    	}

3,Hashtable

  底層是哈希表數據結構,不可以存入null鍵null值。該集合是線程同步的。JDK1.0 效率低

 

擴展練習:

一個學校有多個班級,一個班級有多個學生(學號  姓名)。

拿一個集合來放班級。 (學校---班級)

拿一個集合來放學生。(班級--學生) 

如:

學校集合,存放 班級 

    HashMap<String,HashMap<String,String>> czbk = 
    new HashMap<String,HashMap<String,String>>();
    
    班級集合,存放 學生(學號  姓名)
    HashMap<String,String> yure = new HashMap<String,String>();
    
    HashMap<String,String> jiuye = new HashMap<String,String>();
    
    //學校增加班級
    czbk.put("yureban",yure);
    czbk.put("jiuyeban",jiuye);
    
    //班級增加學生
    yure.put("01","zhansan");
       yure.put("02","lisi");
       jiuye.put("01","wangwu");
       jiuye.put("02","zhaoliu");

          //輸出也是,先取班級,再通過班級取出學生信息。或也可以使用其它的方法來完成,但使用這種方法呢,我們還得對建立Student類,來保存 學生信息,如果使用Map鍵值對呢,就可以不用寫。

       例:

    學校集合,存放 班級
    HashMap<String,List<Student>> czbk = new HashMap<String,List<Student>>();	
    班級集合,存放 學生對象
    List<Student> yure = new ArrayList<Student>();
    List<Student> jiuye = new ArrayList<Student>();
    
    //學生信息
    class Student(){   }  

 

Comparable 與 Comparator 區別?

Comparable :適用於一個類自身具有比較性,即具有自然順序的時候使用。

Comparator : 定義自己的比較方式(比較器),即本身不具備比較性,或具有的比較性,不是把需要的。

 

注意:當兩種排序都存在時,以比較器(Comparator )爲主。(比較常用)

一般寫好的代碼不要去修改,實現接口就行了。(接口:功能擴展)

例:

按字符串長度排序 

字符串本身具備比較性,但是它的比較方式不是所需要的,這時就只能使用比較器Comparator 

TreeSet ts = new TreeSet(new StrLenComparator());

class StrLenComparator implements Comparator //比較器

{

public int compare(Object o1,Object o2)

{

String s1 = (String)o1;

String s2 = (String)o2;

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

if(num==0)

return s1.compareTo(s2);

return num;

}

}

 

Iterator 迭代器

什麼是迭代器?

      就是從集合裏取出元素的方式。

     因爲每一種集合都有取出元素操作,所以把這個取方式封裝成了一個類 Iterator

 

使用方法:

      集合:ArrayList a1 = new ArrayList() ;

       Iterator it = a1.iterator();  //獲取迭代器,用於取出集合中的元素

      while(it.hasNext())   // 正向取出

     {

           System.out.println(it.next());

     }

    注意:在迭代時,不可以通過 集合對象 的方法操作集合中的元素。因爲會發生併發操作異常

               所以,在迭代器時,只能用迭代器的方法操作元素。

   但Iterator方法有限,只能對元素進行判斷,取出,刪除等操作.

 

   List集合特有的迭代器 :ListIterator 

  它可以添加,修改,按任一方向遍歷列表獲得迭代器在列表中的當前位置等。該接口只能通過List集合的ListIterator方法獲取。

              例:

                       ListIterator li = a1.listIterator(al.size()) ; //這裏注意指定指針位置。

                        while(li.hasPrevious())//從後往前取出

                      {

                             System.out.prinln( li.previous() );

                       }

 

心得:

這麼多集合,我們在使用集合的時候要注意應該選用什麼樣的集合,選對集合,對於我們操作對象什麼都是很方便的,List集合中存放的元素是無序的,適用於對元素無須排序,而且元素可以重複出現。Set集合呢,元素是不能重複出現的,存放的元素進行過排列的。適用於要對對象按一定要求進行排序,去除重複元素等。這裏排序工作可以由Compareble或Comparetor (自定義比較器)來完成。Set集合底層就是由Map集合來完成的。Map集合呢,適用於保存那些有映射關係的。List 、Set 集合都是使用Iterator 迭代器來輸出集合內容,對於Liste還有一個特有的ListIterator 迭代方法,這個提供了操作集合的一些方法,如:刪除,修改等。Map集合的輸出要先通過自己的方法,轉換成Set集合,然後Set集合在通過Iteraor來輸出。


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