Java集合類初步瞭解

深情不及久伴OvO發表於2020-11-07

集合概述:
集合按照其儲存結構可以分為兩大類,即單列集合Collection和雙列集合Map,這兩集合的特點具體如下。

Colleetion; 單列集合類的根介面,用於儲存一系列符合某種規則的元素,它有兩個重要的子介面,分別是List和Set。其中,List的特點是元素有序、元素可重複。Set的特點是元素無序並且不可重複。List 介面的主要實現類有ArrayList和LinkedList,Set介面的主要實現類有HashSet和TreeSet;

Map: 雙列集合類的根介面,用於儲存具有健(Key)、值(Value)對映關係的元素,每個元素都包含一對鍵值,在使用Map集合時可以通過指定的Key 找到對應的Value,例如根據一個學生的學號就可以找到對應的學生。Map介面的主要實現類有HashMap和TreeMap;

Collection是所有單列集合的父介面,List介面繼承自Collection介面,習慣將實現了List介面的物件稱為List集合。在List集合中允許出現重複的元素,所有的元素是以一種線性方式進行儲存的,在程式中可以通過索引來訪問集合中的指定元素。另外,List集合還有一個特點就是元素有序,即元素的存人順序和取出順序一致。

ArrayList是List 介面的一個實現類,它是程式中最常見的一種集合。在ArrayList內部封裝了一個長度可變的陣列物件,當存人的元素超過陣列長度時,ArrayList會在記憶體中分配一個更大的陣列來儲存這些元素,因此可以將ArrayList集合看作一個長度可變的陣列。

ArrayList集合中大部分方法都是從父類Collection和List繼承過來的,其中add()方法和get()方法用於實現元素的存取,如例所示。

package Example;
import java.util.*;
public class example01 {
	public static void main(String[] args) {
		ArrayList list = new ArrayList();//建立ArrayList集合
		list.add("stul");
		list.add("stu2");
		list.add("stu3");
		list.add("stu4");
		System.out.println("集合的長度:"+list.size());
		System.out.println("第二個元素是:"+list.get(1));
	}
}

由於ArrayList集合的底層是使用一個陣列來儲存元素,在增加或刪除指定位置的元素時,會導致建立新的陣列,效率比較低,因此不適合做大量的增刪操作。但這種陣列的結構允許程式通過索引的方式來訪問元素,因此使用ArrayList集合查詢元素很便捷。
注意:在編譯例題時,會得到警告,意思是說在使用ArayList集合時並沒有顯示指定集合中儲存什麼型別的元素,會產生安全隱惠,這涉及到泛型安全機制的問題。
LinkedList集合:
克服ArrayList集合增刪元素時效率低的侷限性;

package Example;
import java.util.*;
public class example02 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        LinkedList link = new LinkedList();//建立LinkedList集合
        link.add("stu1");
        link.add("stu2");
        link.add("stu3");
        link.add("stu4");
        System.out.println(link.toString());//取出並列印該集合中的元素
        link.add(3,"Student");//向該集合中指定位置插入元素
        link.addFirst("First");//向該集合第一個位置插入元素
        System.out.println(link);
        System.out.println(link.getFirst());//取出該集合中第一個元素
        link.remove(3);//移除該集合中指定位置的元素
        link.removeFirst();//移除該集合中第一個元素
        System.out.println(link);
	}
}

由此可見,使用LinkedList對元素進行增刪操作是非常便捷的;

Iterator介面:
在程式開發中.經常需要遍歷集合中的所有元素。針對這種需求,JDK專門提供了一個介面Iterator。 Iterator 介面也是Java集合框架中的一員,但它與Collection、 Map介面有所不同.Collection介面與Map介面主要用於儲存元素,而Iterator 主要用於迭代訪問(即遍歷)Collection中的元素,因此Iterator物件也被稱為迭代器。

package Example;
import java.util.*;
public class example03 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub40-
        ArrayList list = new ArrayList();//建立ArrayList集合
        list.add("data_1");//向該集合中新增字串
        list.add("data_2");
        list.add("data_3");
        list.add("data_4");
        Iterator it =list.iterator();//獲取Iterator物件
        while(it.hasNext()) {      //判斷ArrayList集合中是否存在下一個元
        	Object obj = it.next();//取出ArrayList集合中的元素
        	System.out.println(obj);
        }
	}
}

雖然Iterator可以用來遍歷集合中的元素,但寫法上比較煩瑣,為了簡化書寫,從JDK5.0開始,提供了foreach 迴圈。foreach 迴圈是一種更加簡潔的for迴圈,也稱增強for迴圈。foreach迴圈用於遍歷陣列或集合中的元素,其具體語法格式如下:

for(容器中元素型別臨時變數:容器變數) (
執行語句
}

package Example;
import java.util.*;
public class example04 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        ArrayList list = new ArrayList();//建立ArrayList集合
        list.add("Jack");//向ArrayList集合中新增字串元素
        list.add("Rose");
        list.add("Tom");
        for(Object obj:list) {       //使用foreach迴圈遍歷ArrayList物件
        	System.out.println(obj);//取出並列印ArrayList集合中的元素
        }
	}
}

①foreach迴圈雖然書寫起來很簡潔,但在使用時也存在一定的侷限性。當使用foreach迴圈遍歷集合和陣列時,只能訪問集合中的元素,不能對其中的元素進行修改。接下來以一個String型別的陣列為例來進行演示,如例所示。

package Example;
public class example05 {
    static String[] strs= {"aaa","bbb","ccc"};
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        //foreach迴圈遍歷陣列
		for(String str:strs) {
			str="ddd";
		}
		System.out.println("foreach迴圈修改後的陣列:"+strs[0]+","+strs[1]+","+strs[2]);
		//for迴圈遍歷陣列
		for(int i=0;i<strs.length;i++) {
			strs[i]="ddd";
		}
		System.out.println("普通for迴圈修改後的陣列:"+strs[0]+","+strs[1]+","+strs[2]);
	}
}

②在使用Iterator 迭代器對集合中的元素進行迭代時,如果呼叫了集合物件的remove()方法去刪除元素,會出現異常。接下來通過一個案例來演示這種異常。假設在一個集合中儲存了學校所有學生的姓名,由於一個名為Annie的學生中途轉學,這時就需要在選代集合時找出該元素並將其刪除,具體程式碼如例所示。

package Example;
import java.util.*;
public class example06 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        ArrayList list = new ArrayList();//建立ArrayList集合
        list.add("Jack");
        list.add("Annie");
        list.add("Rose");
        list.add("Tom");
        Iterator it = list.iterator(); //獲得Iterator物件
        while(it.hasNext()) {          //判斷該集合是否有下一個元素
        	Object obj = it.next();    //獲取該集合中的元素
        	if("Annie".equals(obj)) {  //判斷該集合中的元素是否為Annie
        		list.remove(obj);//刪除該集合中的元素
        		//解決問題
        		//break;1》只需找到該學生後跳出迴圈不再迭代即可;
        		//it.remove();2》呼叫迭代器本身的刪除方法
        	}
        }
        System.out.println(list);   
	}
}

Listtlterator介面:
ListIterator迭代器是Iterator的子類;使用案例:

package Example;
import java.util.*;
public class example07 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        ArrayList<String> list = new ArrayList();//建立ArrayList集合
        list.add("data_1");
        list.add("data_2");
        list.add("data_3");
        System.out.println(list);
        ListIterator it = list.listIterator(list.size());//獲得ListIterator物件
        while(it.hasPrevious()) {      //判斷該物件是否有上一個元素
        	Object obj = it.previous();//迭代該物件的上一個元素
        	System.out.println(obj+" ");
        }
	}
}

注意:ListIterator迭代器只能用於List集合;
Enumeration介面:
在JDK1. 2以前還沒有Iterator介面的時候,遍歷集合需要使用Enumeration介面,它的用法和Iterator類似。由於很多程式中依然在使用Enumeration.因此瞭解該介面的用法是很有必要的。JDK中提供了一個Vector集合,該集合是List介面的一個實現類,用法與ArrayList 完全相同.區別在於Vector集合是執行緒安全的,面ArrayList集合是執行緒不安全的。在Vector類中提供了一個elements()方法用於返回Enumeration物件,通過Enumeration 物件就可以遍歷該集合中的元素。接下來通過一個示例來演示如何使用Enumeration 物件遍歷Vecor集合.

package Example;
import java.util.*;
public class example08 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        Vector v = new Vector();//建立Vector物件
        v.add("Jack");
        v.add("Rose");
        v.add("Tom");
        Enumeration en = v.elements();//獲得Enumeration物件
        /*該過程與Iterator迭代的過程類似,通過hasMoreElements()方法迴圈判斷是否存在下一個元素,如果存在
                      * 則通過nextElement()方法逐一取出每個元素
         */
        while(en.hasMoreElements()) {     //判斷該物件是否有更多元素
        	Object obj = en.nextElement();//取出該物件的下一個元素 
        	System.out.println(obj);
        }
	}
}

Set介面簡介:
Set介面和 List介面一樣.同樣繼承自Collection介面,,它與Collection介面中的方法基本一致,並沒有對 Clleteo介面進行功能上的擴充,只是比Collection介面更加產格了。與List介面不同的是,Set介面中元素無序.並且都會以某種規則保證存人的元素不出現重複。

Set介面主要有兩個實現類,分別是HashSet和TreeSet。其中.HashSet是根據物件的雜湊值來確定元素在集合中的儲存位置,因此具有良好的存取和查詢效能。TreeSet則是以二叉樹的方式來儲存元素,它可以實現對集合中的元素進行排序。
例1:

package Example;

import java.util.*;

public class example09 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
        HashSet set = new HashSet();//建立HashSet集合
        set.add("Jack");//向Set集合中新增字串
        set.add("Eve");
        set.add("Rose");
        set.add("Rose");//向該集合中新增重複元素
        Iterator it = set.iterator();//獲取Iterator物件
        while(it.hasNext()) {      //通過while迴圈,判斷集合中是否有元素
        	Object obj = it.next();//如果有元素,就通過迭代器的next()方法獲取元素
        	System.out.println(obj);
        }
	}

}

例2:

package Example;
import java.util.*;
class Student{
	private String id;
	private String name;
	public Student(String id,String name) { //建立構造方法
		this.id = id;
		this.name = name;
	}
	//重寫toString()方法
	public String toString(){  
		return id+":"+name;
	}
	//重寫hashCode方法
	public int hashCode() {
		return id.hashCode();//返回id屬性的雜湊值
	}
	//重寫equals方法
	public boolean equals(Object obj) {
		if(this==obj) {  //判斷是否是同一個物件
			return true; //如果是,直接返回true
		}
		if(!(obj instanceof Student)) { //判斷物件是否為Student型別
			return false;//如果物件不是Student型別,返回false
		}
		Student stu = (Student) obj;//將物件強制轉換為Student型別
		boolean b = this.id.equals(stu.id);//判斷id值是否相同
		return b;
	}
}
public class example10 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        HashSet hs = new HashSet();//建立HashSet集合
        Student stu1 = new Student("1","Jack");//建立Student物件
        Student stu2 = new Student("2","Rose");
        Student stu3 = new Student("2","Rose");
        hs.add(stu1);
        hs.add(stu2);
        hs.add(stu3);
        System.out.println(hs);
	}
}

根據前面的分析不難看出,當向集合中存人元素時,為了保證HashSet正常工作,要求在存人物件時,重寫該類中的hashCode()和equals()方法。例中將字串存人HashSet時,Sring類已經重寫了hashCode()和equals()方法。但是如果將Student物件存入HashSet,結果如何?
在例2中,向HashSet集合存人三個Student物件、並將這三個物件迭代輸出。執行結果中出現了兩個相同的學生資訊“2:Rose",這樣的學生資訊應該被視為重複元素,不允許同時出現在HashSet集合中。之所以沒有去掉這樣的重複元素是因為在定義Student 類時沒有重寫hashCode()和equals()方法。
上述程式例二已修改;

TreeSet集合:
TreeSet是Set介面的另一個實現類,它內部採用自平衡的排序二叉樹來儲存元素,這樣的結構可以保證TreeSet集合中沒有重複的元素,並且可以對元素進行排序。例:

package Example;
import java.util.*;
public class example11 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        TreeSet ts = new TreeSet();//建立TreeSet集合
        ts.add("Jack");//向TreeSet集合中新增元素
        ts.add("Helena");
        ts.add("Helena");
        ts.add("Eve");
        Iterator it = ts.iterator();//獲取Iterator物件
        while(it.hasNext()) {
        	System.out.println(it.next());
        }
	}
}

集合中的元素在進行比較時,都會呼叫compareTo()方法,該方法是Comparable介面中定義的,因此要想對集合中的元素進行排序,就必須實現Comparable介面。JDK中大部分的類都實現Comparable介面,擁有了介面中的CompareTo()方法,如Integer、Double和String等。在TreeSet集合中存放Student型別物件時,如果Student類沒有實現Comparable介面,則Student型別的物件將不能進行比較,這時,TreeSet集合就不知道按照什麼排序規則對Student物件進行排序,最終導致程式報錯。因此,為了在TreeSet 集合中存放Student物件,必須使Student類實現Comparable介面,如例所示。

package Example;
import java.util.*;
class Student implements Comparable{//定義Student類實現Comparable介面
	String name;
	int age;
	public Student(String name,int age) {//建立構造方法
		this.name = name;
		this.age = age;
	}
	public String toString() {//重寫Object類的toString()方法,返回描述資訊
		return name+":"+age;
	}
	public int compareTo(Object obj) {
		Student s = (Student) obj;//將比較的物件強制轉化為Student型別
		if(this.age - s.age>0) {//定義比較方式
			return 1;
		}
		if(this.age - s.age == 0) {
			return this.name.compareTo(s.name);//將比較結果返回
		}
		return -1;
	}
}
public class example12 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TreeSet ts = new TreeSet();//建立TreeSet集合
        ts.add(new Student("Jack",19));//向集合中新增元素
        ts.add(new Student("Rose",18));
        ts.add(new Student("Tom",19));
        ts.add(new Student("Rose",18));
        Iterator it = ts.iterator();//獲取Iterator物件
        while(it.hasNext()) {
        	System.out.println(it.next());
        }
	}
}

有時候,定義的類沒有實現Comparable介面或者實現了Comparable 介面而不想按照定義的compareTo()方法進行排序。例如,希望字串可以按照長度來進行排序,這時,可以通過自定義比較器的方式對TreeSet集合中的元素排序,即實現Comparator介面,在建立TreeSet集合時指定比較器。接下來通過一個案例來演示TreeSet集合中字串按照長度進行排序,如例所示:

package Example;
import java.util.*;
class MyComparator implements Comparator{ //定義比較方法實現Comparator介面
	public int compare(Object obj1,Object obj2) {//定義比較方法
		String s1 = (String) obj1;
		String s2 = (String) obj2;
		int temp = s1.length()-s2.length();
		return temp;
	}
}
public class example13 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        TreeSet ts = new TreeSet(new MyComparator());
        //建立TreeSet物件時傳入自定義比較器
        ts.add("Jack");//向該Set物件中新增字串
        ts.add("Helena");
        ts.add("Eve");
        Iterator it=ts.iterator();//獲取Iterator物件
        //通過while迴圈,逐漸將集合中的元素列印出來
        while(it.hasNext()) {
        	//如果Iterator有元素進行迭代,則獲取元素並進行列印
        	Object obj=it.next();
        	System.out.println(obj);
        }
	}
}

Map介面:
Map介面是一種雙列集合,它的每個元素都包含一個鍵物件Key和一個值物件Value, 鍵和值物件之間存在一種對應關係,稱為對映。從Map集合中訪問元素時,只要指定了Key,就能找到對應的Value。
HashMap集合是Map介面的一個實現類,它用於儲存鍵值對映關係,但必須保證不出現重複的鍵。例:

package Example;
import java.util.*;
public class example03 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        Map map=new HashMap();//建立Map物件
        map.put("1", "Jack");//儲存鍵和值
        map.put("2", "Rouse");
        map.put("3", "Lucy");
        map.put("3", "Mary");//鍵相同,值覆蓋
        System.out.println("1:"+map.get("1"));//根據鍵獲取值
        System.out.println("2:"+map.get("2"));
        System.out.println("3:"+map.get("3"));
	}
}

程式開發中經常需要取出Map中所有的鍵和值,如何遍歷Map中的鍵值對?

package Example;
import java.util.*;
public class example04 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        Map map=new HashMap();//建立Map物件
        map.put("1", "Jack");//儲存鍵和值
        map.put("2", "Rouse");
        map.put("3", "Lucy");
        /*第一種遍歷Map的方式:首先呼叫Map物件的keySet()方法,獲得儲存Map中所有鍵的Set集合,然後通過Iterator迭代Set集合的每一個元素
                        * 即每一個鍵,最後通過呼叫get(String key)方法,根據鍵獲取對應的值;
         */
        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);
        }
	}
}
package Example;
import java.util.*;
public class example05 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        Map map = new HashMap();//建立Map集合
        map.put("1", "Jack");//儲存鍵和值
        map.put("2", "Rose");
        map.put("3","Lucy");
        /*第二種遍歷Map的方式:首先呼叫Map物件的entrySet()方法獲得儲存在Map中所有對映的Set集合,這個集合中存放了Map,Entry型別的
                       * 元素(Entry是Map介面內部類),每個Map.Entry物件代表Map中的一個鍵值對,然後迭代Set集合,獲得每一個對映物件,並分別呼叫對映
                       *物件的getKey()和getValue()方法獲取鍵和值;·
         */
        Set entrySet=map.entrySet();
        Iterator it = entrySet.iterator();//獲取Iterator物件
        while(it.hasNext()) {
        	Map.Entry entry = (Map.Entry)(it.next());//獲取集合中鍵值對對映關係
        	Object key = entry.getKey();//獲取Entry中的鍵
        	Object value = entry.getValue();//獲取Entry中的 值
        	System.out.println(key+":"+value);
        }
	}
}
package Example;
import java.util.*;
public class example06 {
/*Map中提供了一個values()方法,通過這個方法可以直接獲取Map中儲存所有值的Collection集合;
 * 從執行結果可以看出HashMap集合迭代出來的元素的順序和存入的順序不一致。
 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        Map map = new HashMap();//建立Map集合
        map.put("1","Jack");//儲存鍵和值
        map.put("2","Rose");
        map.put("3","Lucy");
        Collection values = map.values();
        Iterator it = values.iterator();
        while(it.hasNext()) {
        	Object value = it.next();
        	System.out.println(value);
        }
	}
}
package Example;
import java.util.*;
public class example07 {
//如果想讓HashMap集合迭代出來的元素的順序和存入順序一致,使用LinkedHashMap類,它是HashMap的子類;
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        Map map = new HashMap();//建立Map集合
        map.put("1","Jack");//儲存鍵和值
        map.put("2","Rose");
        map.put("3","Lucy");
        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);
        }
	}
}

TreeMap集合:
用來儲存鍵值對映關係,其中不允許出現重複的鍵;在TreeMap中是通過二叉樹的原理來保證鍵的唯一性;

package Example;
import java.util.*;
public class example01 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TreeMap tm = new TreeMap();
		tm.put("1","Jack");
		tm.put("2","Rose");
		tm.put("3","Lucy");
		Set keySet = tm.keySet();//獲取鍵的集合
		Iterator it = keySet.iterator();//獲取Iterator物件
		while(it.hasNext()) {  //判斷是否存在下一個元素
			Object key = it.next();//取出元素
			Object value = tm.get(key);//根據獲取的鍵找到對應的值
			System.out.println(key+":"+value);
		}
	}
}
package Example;
import java.util.*;
/*使用TreeMap集合時,通過自定義比較器的方式對所有的鍵進行排序;
 * 下面定義了比較器MyComparator針對String型別的id進行比較,在實現compare()方法時,呼叫了String物件的compareTo()方法;由於
 * 方法中返回的是“id2.compareTo(id1)”,所以輸出結果中的id按照與字典順序相反的順序進行排序;
 */

public class example02 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
        TreeMap tm = new TreeMap(new MyComparator());//傳入一個自定義比較器
		tm.put("1","Jack");//向集合中存入學生的學號和姓名
		tm.put("2","Rose");
		tm.put("3","Lucy");
		Set keySet = tm.keySet();//獲取鍵的集合
		Iterator it = keySet.iterator();//獲取Iterator物件
		while(it.hasNext()) {  //判斷是否存在下一個元素
			Object key = it.next();//取出元素
			Object value = tm.get(key);//根據獲取的鍵找到對應的值
			System.out.println(key+":"+value);
		}
	}
}
class MyComparator implements Comparator{ //自定義比較器
	public int compare(Object obj1,Object obj2) { //實現比較方法
		String id1=(String) obj1; //將Object型別的引數強轉為String型別
		String id2=(String) obj2;
		return id2.compareTo(id1);//將比較之後的值返回
	}
}

Properties集合:
Map介面中的一個實現類Hashtable,與HashMap的區別:Hashtable是執行緒安全的。Hashtable存取元素時速度很慢,目前基本上被HashMap類所取代,但Hashtable 類有一個子類Properties在實際應用中非常重要,Propertiesz主要用來儲存字串型別的鍵和值,在實際開發中,經常使用Properties集合來存取應用的配置項。假設有一個文字編輯工具,要求預設背景色是紅色,字型大小為14px,語言為中文,其配置項應該如下:
Backgroup-color = red
Front-Size = 14px
Language = chinese
通過Prorpertites集合對這些配置項進行存取:

package Example;
import java.util.*;
public class example03 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        Properties p = new Properties();//建立Properties物件
        p.setProperty("backgroup-color", "red");
        p.setProperty("Font-size", "14px");
        p.setProperty("Language", "chinese");
        Enumeration names = p.propertyNames();//獲取Enumeration物件所有鍵的列舉
		while(names.hasMoreElements()) { //迴圈遍歷所有的鍵
        	String key = (String) names.nextElement();
        	String value = p.getProperty(key);//獲取對應鍵的值
        	System.out.println(key+"="+value);
        }
	}   
}

Properties類中,針對字串的存取提供了兩個專用的方法setProperty()和getProperty()。setProperty()方法用於將配置項的鍵和值新增到Properties集
合當中。在第8行程式碼中通過呼叫Properties 的propertyNames()方法得到一個包含所有鍵的Enumeration物件,然後在遍歷所有的鍵時,通過呼叫getProperty()方法獲得鍵所對應的值;

相關文章