1. 程式人生 > >黑馬程式設計師——java的集合類

黑馬程式設計師——java的集合類

------- android培訓java培訓、期待與您交流! ----------

前言:通過觀看畢向東老師的java基礎視訊,查漏補缺,將一些自己掌握的還不牢固的知識寫出來,希望和大家交流分享。

1.集合框架

1.集合類的出現原因:為了方便對多個物件的操作,就對物件進行儲存,集合就是儲存物件最常用的一種方式。

2.java集合框架的構成,由於資料結構的不同,有不同的集合,也叫容器。如下圖:

3.與陣列相比,集合的優勢:  陣列雖然也可以儲存物件,但長度是固定的;集合長度是可變的。陣列中可以儲存基本資料型別,集合只能儲存物件。

2.Collection類

1.Collection的結構:

   Collection

         |--List//元素是有序的,元素可以重複。因為該集合體繫有索引。

         |--Set//元素是無序的,元素不可以重複。

2.Collection介面中常見方法

  1)add(Object obj); //新增元素,add方法的引數型別是Object。以便於接收任意型別物件。

  2) 刪除元素

         remove(Objectobj);

          removeAll(另一集合);//呼叫者只保留另一集合中沒有的元素。

          clear();//清空集合

   3)判斷元素

        contains(Objectobj);//判斷是否存在obj這個元素

        isEmpty();//是否為空

     4)size();//獲取個數,集合長度

     5)  retainAll(另一集合);//呼叫者只保留兩集合的共性元素。

     注:集合中儲存的都是物件的引用(地址)。

3.迭代

   1) 迭代是取出集合中元素的一種方式。

   2)Iterator規則:對於集合的元素取出這個動作被定義成了內部類,可以直接訪問集合內部的元素。對每一個容器的資料結構不同,所以取出的動作細節也不一樣。

        但是都具有共性內容: 判斷和取出。那麼就可以將這些共性抽取。 那麼這些內部類都符合一個規則(或者說都抽取出來一個規則)。該規則就是Iterator。

        通過一個對外提供的方法:iterator();,來獲取集合的取出物件。因為Collection中有iterator方法,所以每一個子類集合物件都具備迭代器。

   3)三個方法:

      hasNext();//有下一個元素,返回真

        next();//取出下一個元素

        remove();//移除

        注:在迭代時迴圈中next呼叫一次,就要hasNext判斷一次

       如:

        ArrayList a=newArrayList();//建立一個集合
        Iteratorit=a.iterator();//獲取一個迭代器,用於取出集合中的元素。
        //第一種列印方式:
        for(Iterator iter = a.iterator();iter.hasNext();){
                System.out.println(iter.next());
        }
        //第二種列印方式:
        Iterator iter = a.iterator();
        while(iter.hasNext()){
            System.out.println(iter.next());
         } 
      4)注意事項:

       迭代器在Collcection介面中是通用的,它替代了Vector類中的Enumeration(列舉)。

       迭代器的next方法是自動向下取元素,要避免出現NoSuchElementException。

       迭代器的next方法返回值型別是Object,所以要記得型別轉換。

3.List類

1.list的組成結構

       List:元素是有序的,元素可以重複。因為該集合體繫有索引。

            |--ArrayList:底層的資料結構使用的是陣列結構。特點:查詢速度很快。但是增刪稍慢。執行緒不同步。

            |--LinkedList:底層使用的是連結串列資料結構。特點:增刪速度很快,查詢稍慢。

            |--Vector:底層是陣列資料結構。執行緒同步。被ArrayList替代了。

2.List的特有方法:

   凡是可以操作角標的方法都是該體系特有的方法。

   1)增

        boolean add(index,element);//指定位置新增元素

        Boolean addAll(index,Collection);//在指定位置增加給定集合中的所有元素,若省略位置引數,則在當前集合的後面依次新增元素

   2)刪

        Boolean remove(index);//刪除指定位置的元素

   3)改

        set(index,element);//修改指定位置的元素。

   4)查

        get(index);//通過角標獲取元素

        subList(from,to);//獲取部分物件元素

    5)其他

        listIterator();//List特有的迭代器

        indexOf(obj);//獲取元素第一次出現的位置,如果沒有則返回-1

        注:List集合判斷元素是否相同,移除等操作,依據的是元素的equals方法。

 3.ListIterator 是List集合特有的迭代器,是Iterator的子介面,對Iterator進行了擴充套件。

    ListIterator特有的方法:

        add(obj);//增加

        set(obj);//修改為obj

        hasPrevious();//判斷前面有沒有元素

        previous();//取前一個元素

4.Vector中的列舉Enumeration

   1、列舉就是Vector特有的取出方式
   2、發現列舉和迭代器很像。
   3、其實列舉和迭代是一樣的,因為列舉的名稱以及方法的名稱都過長,所以被迭代器取代了

5.LinkedList

   它底層使用的是連結串列資料結構。特點:增刪速度很快,查詢稍慢。

   特有方法:

     1、增

         addFirst();

         addLast();

      2、獲取

        //獲取元素,但不刪除元素。如果集合中沒有元素,會出現NoSuchElementException

        getFirst();

        getLast();

       3、刪

        //獲取元素,並刪除元素。如果集合中沒有元素,會出現NoSuchElementException

        removeFirst();

        removeLast();

        在JDK1.6以後,出現了替代方法。

      1、增

        offFirst();

        offLast();

       2、獲取

        //獲取元素,但是不刪除。如果集合中沒有元素,會返回null。

        peekFirst();

        peekLast();

        3、刪

        //獲取元素,並刪除元素。如果集合中沒有元素,會返回null。

        pollFirst();

        pollLast();

       LinkedList程式碼示例:
package collection;

import java.util.LinkedList;

/**
 * 使用LinkedList模擬一個堆疊或者佇列資料結構。
 * 堆疊:先進後出  如同一個杯子。 
 * 佇列:先進先出 FIFO 如同一個水管。 
 * @author songwenju
 *
 */
public class LinkedListDemo {
	//模擬棧
	public static void stack(LinkedList<String> list){
		while (!list.isEmpty()) {
			System.out.println(list.removeFirst());
		}
	}
	
	//模擬佇列
	public static void queue(LinkedList<String> list){
		while (!list.isEmpty()) {
			System.out.println(list.removeLast());
		}
	}
	
	public static void main(String[] args) {
		LinkedList<String> list = new LinkedList<String>();
		list.addFirst("java01");
		list.addFirst("java02");
		list.addFirst("java03");
		list.addFirst("java04");
		list.addFirst("java05");
		
		//堆疊輸出
		//stack(list);
		//佇列輸出
		queue(list);
	}
}
4.Set類

1.Set的組成結構

     Set:元素是無序(存入和取出的順序不一定一致),元素不可以重複。     

           |--HashSet:底層資料結構是雜湊表。執行緒不同步。 保證元素唯一性的原理:判斷元素的hashCode值是否相同。如果相同,還會繼續判斷元素的equals方法,是否為true。

           |--TreeSet:可以對Set集合中的元素進行排序。預設按照字母的自然排序。底層資料結構是二叉樹。保證元素唯一性的依據:compareTo方法return 0。

        Set集合的功能和Collection是一致的。


2.HashSet

  1)HashSet:執行緒不安全,存取速度快。

  2)可以通過元素的兩個方法,hashCode和equals來完成保證元素唯一性。

       如果元素的HashCode值相同,才會判斷equals是否為true。如果元素的hashCode值不同,不會呼叫equals。

  3)HashSet對於判斷元素是否存在,以及刪除等操作,依賴的方法是元素的hashCode和equals方法。

程式碼示例:

package collection;

import java.util.HashSet;

/**
 * 往hashSet集合中存入自定義物件 
 * 姓名和年齡相同為同一個人,重複元素。去除重複元素 
 * 思路:
 *     1、對人描述,將人的一些屬性等封裝進物件 
 *     2、定義一個HashSet容器,儲存人物件 
 *     3、取出 
 * @author songwenju
 *
 */
class Person{
	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 int getAge() {
		return age;
	}
	//以下hashCode和equals是由eclipse生成的程式碼。
	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (!(obj instanceof Person)) {
			return false;
		}
		Person other = (Person) obj;
		if (age != other.age) {
			return false;
		}
		if (name == null) {
			if (other.name != null) {
				return false;
			}
		} else if (!name.equals(other.name)) {
			return false;
		}
		return true;
	}
	
}
public class HashSetDemo {
	public static void main(String[] args) {
		HashSet<Person> h = new HashSet<Person>();
		h.add(new Person("stu1", 10));
		h.add(new Person("stu2", 6));
		h.add(new Person("stu3", 30));
		h.add(new Person("stu1", 10));
		h.add(new Person("stu4", 10));
		
		for (Person p : h) {
			System.out.println(p.getName()+"-->"+p.getAge());
		}
	}
}
執行結果:

分析:重複元素去重。

3.TreeSet

   1) 底層的資料結構為二叉樹結構(紅黑樹結構)

   2)可對Set集合中的元素進行排序,是因為:TreeSet類實現了Comparable介面,該介面強制讓增加到集合中的物件進行了比較,需要複寫compareTo方法,才能讓物件按指定需求(如人的年齡大小比較等)進行排序,並加入集合。

   3) java中的很多類都具備比較性,其實就是實現了Comparable介面。

   4)排序時,當主要條件相同時,按次要條件排序。

  5)保證資料的唯一性的依據:通過compareTo方法的返回值,是正整數、負整數或零,則兩個物件較大、較小或相同。相等時則不會存入。

  6)Tree排序的兩種方式

       1、方式一,自然排序:讓元素自身具備比較性。元素需要實現Comparable介面,覆蓋compareTo方法。這種方式也被稱為元素的自然順序,或者叫做預設順序。

       程式碼示例:

package collection;

import java.util.TreeSet;

/**
 * 自然排序
 * @author songwenju
 *
 */
//這裡要實現Compare介面,否則會報collection.Student cannot be cast to java.lang.Comparable錯誤
class Student implements Comparable<Student>{
	
	private String name;
	private int age;
	
	public Student() {}
	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public int getAge() {
		return age;
	}

	//覆寫compareTo
	@Override
	public int compareTo(Student student) {
		if (this.age == student.age) {
			return this.name.compareTo(student.name);
		}
		return this.age - student.age;
	}
	
}
public class TreeSetDemo {
	public static void main(String[] args) {
		TreeSet<Student> t = new TreeSet<Student>();
		t.add(new Student("stu1", 12));
		t.add(new Student("stusj", 2));
		t.add(new Student("stu1swj", 12));
		t.add(new Student("stu6ds", 12));
		t.add(new Student("stu", 22));
		
		for (Student p : t) {
			System.out.println(p.getName()+"-->"+p.getAge());
		}
	}
}
   執行結果:

  

        2、方式二,比較器:當元素自身不具備比較性時,或者具備的比較性不是所需要的。這時就需要讓集合自身具備比較性。

        在集合初始化時,就有了比較方式。定義一個比較器,將比較器物件作為引數傳遞給TreeSet集合的建構函式。

        比較器構造方式:定義一個類,實現Comparator介面,覆蓋compare方法。

        當兩種排序都存在時,以比較器為主。

        程式碼示例:

package collection;

import java.util.Comparator;
import java.util.TreeSet;

/**
 * 往TreeSet集合中儲存自定義物件學生。 
 * 想按照學生的年齡進行排序。 
 * @author songwenju
 *
 */
//這裡要實現Compare介面,否則會報collection.Student cannot be cast to java.lang.Comparable錯誤
class Student implements Comparable<Student>{
	
	private String name;
	private int age;
	
	public Student() {}
	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public int getAge() {
		return age;
	}

	//覆寫compareTo
	@Override
	public int compareTo(Student student) {
		if (this.age == student.age) {
			return this.name.compareTo(student.name);
		}
		return this.age - student.age;
	}
	
}
//定義一個比較器
class LenCompare implements Comparator<Student>{

	@Override
	public int compare(Student s1, Student s2) {
		int num = new Integer(s1.getName().length()).compareTo(new Integer(s2.getName().length()));
		if (num == 0) {
			return new Integer(s1.getAge()).compareTo(s2.getAge());
		}
		return 0;
	}
	
}
public class TreeSetDemo {
	public static void main(String[] args) {
		TreeSet<Student> t = new TreeSet<Student>();
		t.add(new Student("stu1", 12));
		t.add(new Student("stu1", 12));
		t.add(new Student("stusj", 2));
		t.add(new Student("stu1swj", 12));
		t.add(new Student("stu6ds", 12));
		t.add(new Student("stu", 22));
		
		for (Student p : t) {
			System.out.println(p.getName()+"-->"+p.getAge());
		}
	}
}
 執行結果:

 

5.Map集合

1.  Map<K,V>集合是一個介面,和List集合及Set集合不同的是,它是雙列集合,並且可以給物件加上名字,即鍵(Key)

2.該集合儲存鍵值對,一對一對往裡存。要保證鍵的唯一性。

3.Map的組成結構

         Map

            |--Hashtable:底層是雜湊表資料結構,不可以存入null鍵 null值。該集合是執行緒同步的。JDK1.0,效率低。

            |--HashMap:底層是雜湊表資料結構。允許使用null鍵null值,該集合是不同步的。JDK1.2,效率高。

            |--TreeMap:底層是二叉樹資料結構。執行緒不同步。可以用於給Map集合中的鍵進行排序。

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

4.Map集合常用方法

       1、新增

        V  put(K key,V value);//新增元素,如果出現新增時,相同的鍵,那麼後新增的值會覆蓋原有鍵對應值,並put方法會返回被覆蓋的值。

        void putAll(Map <? extends K,? extends V> m);//新增一個集合

        2、刪除

        clear();//清空

        V  remove(Object key);//刪除指定鍵值對

        3、判斷

        containsKey(Objectkey);//判斷鍵是否存在

        containsValue(Objectvalue)//判斷值是否存在

        isEmpty();//判斷是否為空

        4、獲取

        V  get(Object key);//通過鍵獲取對應的值

        size();//獲取集合的長度

        Collection<V>value();//獲取Map集合中所以得值,返回一個Collection集合

        還有兩個取出方法,接下來會逐個講解:

        Set<Map.Entry<K,V>> entrySet();

        Set<K>  keySet();

       注:HashMap集合可以通過get()方法的返回值來判斷一個鍵是否存在,通過返回null來判斷。

5.Map集合的兩種取出方式

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

  1、Set<K> keySet():將Map中所以的鍵存入到Set集合。因為Set具備迭代器。先通過迭代方式取出所以鍵的值,再通過get方法。獲取每一個鍵對應的值。

程式碼示例:

package collection;
import java.util.HashMap;
/**
 * 對Map進行遍歷輸出
 * @author songwenju
 *
 */
public class MapDemo {
    public static void main(String[] args) {
        HashMap<String, String> map = new HashMap<String, String>();
        map.put("河南", "鄭州");
        map.put("河北", "石家莊");
        map.put("湖南", "長沙");
        map.put("湖北", "武漢");
        
        //對keyset進行遍歷,得到每一個key再得到對於的value。
        for (String k : map.keySet()) {
            System.out.print(k + "-->");
            System.out.println(map.get(k));
        }
    }
}
執行結果:

2、Set<Map.Entry<K,V>>   entrySet():將Map集合中的對映關係存入到Set集合中,而這個關係的資料型別就是:Map.Entry       其實,Entry也是一個介面,它是Map介面中的一個內部介面。關係如下:

 interface Map {  
      public static interface Entry{  
            public abstract Object getKey();  
            public abstract Object getValue();  
       }  
  }  

程式碼示例:
package collection;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
 * 對Map進行遍歷輸出
 * @author songwenju
 *
 */
public class MapEntryDemo {
	public static void main(String[] args) {
		HashMap<String, String> map = new HashMap<String, String>();
		map.put("河南", "鄭州");
		map.put("河北", "石家莊");
		map.put("湖南", "長沙");
		map.put("湖北", "武漢");
		
		/*
		 * 用for each實現
		 */
		//對keyset進行遍歷,得到每一個key再得到對於的value。
		Set<Map.Entry<String, String>> entries = map.entrySet();
		for (Entry<String, String>  k : entries) {
			System.out.print(k.getKey() + "-->");
			System.out.println(k.getValue());
		}
		System.out.println("----------------------");
		/*
		 * 用Iterator迭代實現
		 */
		Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
		while (it.hasNext()) {
			Map.Entry<String, String> me = it.next();
			System.out.print(me.getKey() + "-->");
			System.out.println(me.getValue());
		}
		
	}
}
執行結果:

5.Entry是一個介面,它是Map的子介面中的一個內部介面,就相當於是類中有內部類一樣。為何要定義在其內部呢?

        原因:a、Map集合中村的是對映關係這樣的兩個資料,是先有Map這個集合,才可有對映關係的存在,而且此類關係是集合的內部事務。

                  b、並且這個對映關係可以直接訪問Map集合中的內部成員,所以定義在內部。

6.當量資料之間存在著對映關係的時候,就應該想到使用Map集合。

‘如:獲取該字串中的字母出現的次數,如:"sjokafjoilnvoaxllvkasjdfns";希望列印的結果是:a(3)c(0).....

        通過結果發現,每個字母都有對應的次數,說明字母和次數之間有對映關係。

  程式碼示例:

package collection;

import java.util.Map.Entry;
import java.util.TreeMap;

/**
 * 需求: 獲取該字串中的字母出現的次數,如:"sjokafjoilnvoaxllvkasjdfns";希望列印的結果是:a(3)c(1).....
 * 思路:
 *    1、將字串轉換為字元陣列 
 *    2、定義一個TreeMap集合,用於儲存字母和字母出現的次數 
 *    3、用陣列去遍歷集合,如果集合中有該字母則次數加1,如果集合中沒有則存入 
 *    4、將TreeMap集合中的元素轉換為字串 
 * @author songwenju
 *
 */
public class CharCount {
	public static void main(String[] args) {
		String s = "agk;sjaksd;gsa";
		System.out.println("s中各字母出現的個數:"+charCount(s));
	}
	public static String  charCount(String str) {
		char[] chs = str.toCharArray();//轉化為字元陣列
		
        //定義一個TreeMap集合,因為TreeMap集合會給鍵自動排序  
		TreeMap<Character, Integer> map = new TreeMap<Character, Integer>();
		
		int count = 0;//定義計數變數  
		for (int i = 0; i < chs.length; i++) {
			if (!(chs[i]>='a' && chs[i]<= 'z'||chs[i]>='A' && chs[i]<= 'Z')) {
				continue;//如果字串中非字母,則不計數 
			}else {
				Integer value = map.get(chs[i]);//獲取集合中的值 
				if (value != null) {//如果集合中沒有該字母,則存入  
					count = value;
				}
				count++;
				map.put(chs[i], count);
				count = 0;
			}
		}
		
		StringBuilder sBuilder = new StringBuilder();
		
		for (Entry<Character, Integer> c : map.entrySet()) {
			sBuilder.append(c.getKey()+"("+c.getValue()+")");
		}
		return sBuilder.toString();
	}
}

執行結果:


  ------- android培訓java培訓、期待與您交流! ----------