06_集合框架

一、集合概論

(1)、爲什麼出現集合類?

面嚮對象語言對實物的體現都是以對象的形式,所以爲了方便對多個對象的操作,就對對象進行存儲,集合就是存儲最常用的一種方式。

(2)、集合和集合類同時容器,有何不同?

數組雖然也可以存儲對象,但長度是固定的,集合長度是可變的

數組中可以存儲基本數據類型,集合只能存儲對象。

(3)、集合類的特點:

集合只用於存儲對象,集合的長度是可變的,集合可以存儲不同類型的對象。



二、集合常用的方法

(1)、增加:

add();將指定的對象存儲到集合容器中

addAll() 將指定集合中的元素添加到調用方法集合中

(2)、刪除

remove()將指定集合元素添加到調用該方法的集合中。

removeAll()將指定集合中的元素刪除

(3)、修改:

clear()清空集合中的所有元素

(4)、判斷

isEmpty() 判斷集合是否爲空

contains()判斷集合中是否包含指定對象 使用equals()判斷兩個對象是否相等

containsAll(0判斷集合中是否包含指定集合 使用equals()判斷兩個對象是否相等。

(5)、獲取

size()返回集合容器的大小

程序示例:

import java.util.*;

/*
 1.add方法的參數類型是object。以便接受任意類型對象。
 2.集合存儲的都是對象的引用(地址)
 */
public class CollectionDeno1 {
	public static void main(String[] args) {
		ArrayList al = new ArrayList();// 創建一個集合容器。使用collection接口的子類。ArrayList

		// 1.添加元素
		al.add("java01");
		al.add("java02");
		al.add("java03");
		al.add("java04");

		sop("原集合:" + al);// 打印原集合

		// 2.獲取個數。集合長度
		sop("原集合:" + "size:" + al.size());

		// 3.刪除元素。
		al.remove("java02");
		// al.clear();//清空集合

		sop("改變後的集合:" + al);// 打印改變後的集合

		// 4.判斷元素
		sop("java03存在:" + al.contains("java03"));// 判斷java03是否存在
		sop("集合是否爲空?" + al.isEmpty());// 判斷集合是否爲空

	}

	public static void sop(Object obj) {
		System.out.println(obj);
	}
}

(6)、查看集合裏面的所有元素轉換方法:

toArray()返回包含collection中所有元素的數組

(7)、Iterable迭代器 該類主要用來便利集合對象,該類描述了遍歷集合的常用迭代方法。

1、hashNext()如果有元素可以迭代,就返回true;

2、next()返回下一個元素。如果沒有下一個元素,調用元素會拋出NoSuchElementExcepton

3、remover()從迭代器指向的集合中移除迭代器返回的最後一個元素

4、迭代器 遊戲或指針,其實就是調用了ArrayList.get() index++;

      程序示例:

import java.util.*;

/*
 * 什麼是迭代器
 * 其實就是集合的取出元素的方式。
 */

public class CollectionDemo2 {
	public static void main(String[] args) {
		method_get();
	}

	public static void method_get() {
		ArrayList a1 = new ArrayList();
		// 添加元素
		a1.add("java01");// add(Object obj);
		a1.add("java02");
		a1.add("java03");
		Iterator it = a1.iterator();// 獲取迭代器,用於取出集合中的元素
		while (it.hasNext()) {
			sop(it.next());
		}
	}

	public static void sop(Object obj) {
		System.out.println(obj);
	}
}

三、List集合

Collection:

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

                  |--Set :元素無序,元素不可以重複

         List本身也是一個抽取出來的接口

(1)、特有方法:凡是可以操作角標的方法都是該體系特有的方法

add(index,element);

addAll(index,Collection);

刪 

 remove(index);

set(index,elemet);

get(index);

subList(from,to);

listIterator();

//List的特有方法,凡是可以操作角標的方法都是該體系特有的方法,就是增、刪、改、查
import java.util.*;

public class ListDemo1 {

	public static void main(String[] args) {
		ArrayList al = new ArrayList();

		// 添加元素
		al.add("java01");
		al.add("java02");
		al.add("java03");

		sop("原集合是:" + al);

		// 在指定的位置添加元素,在角標爲1的位置添加元素java09
		al.add(1, "java09");
		sop("添加元素後的集合是:" + al);

		// 刪除指定位置的元素
		al.remove(2);
		sop("刪除指定位置元素的集合是:" + al);

		// 修改指定位置的元素
		al.set(2, "java07");
		sop("修改指定位置元素後的集合是:" + al);

		// 通過角標獲取元素
		sop("get(1):" + al.get(1));

		// 獲取所有元素
		for (int x = 0; x < al.size(); x++) {
			System.out.println("al(" + x + ")=" + al.get(x));
		}
	}

	public static void sop(Object obj) {
		System.out.println(obj);

	}
}

(2)、List子類

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

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

Vector:底層數據結構使用的是數組結構。特有的取出方式是枚舉。線程同步,被ArrayList替代了。

/*使用LinkedList模擬一個堆棧或者隊列數據結構。
 * 
 * 堆棧:先進後出。。。如同一個杯子
 * 隊列:先進先出。。。如同一個水管
 */
import java.util.*;

public class LinkedListTest {

	public static void main(String[] args) {
		DuiLie d1 = new DuiLie();

		d1.myAdd("java0001");
		d1.myAdd("java0002");
		d1.myAdd("java0003");
		d1.myAdd("java0004");
		while (!d1.isNull()) {
			System.out.println(d1.myGet());
		}
	}
}

class DuiLie {
	private LinkedList link;

	DuiLie() {
		link = new LinkedList();
	}

	public void myAdd(Object obj) {
		link.addFirst(obj);
	}

	public Object myGet() {
		return link.removeLast();
	}

	public boolean isNull() {
		return link.isEmpty();
	}
}

(3)、Vector特有的方法

import java.util.*;

public class LinkedListDemo {
	public static void main(String[] args) {
		LinkedList ls = new LinkedList();
		ls.addFirst("java001");
		ls.addFirst("java002");
		ls.addFirst("java003");
		ls.addFirst("java004");

		// sop(ls);// 打印結果,本末倒置[java004, java003, java002, java001]
		// sop("size=" + ls.size());
		// sop(ls.getFirst());// 獲取第一個元素,但是不刪除元素

		// sop(ls.removeFirst());// 獲取第一個元素,並刪除元素

		// 不用迭代器,獲取集合中所有的元素
		while (!ls.isEmpty()) {
			sop(ls.removeLast());
		}
	}

	public static void sop(Object obj) {
		System.out.println(obj);
	}
}
如果集合爲空,會出現NoSuchElementException異常。

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

offerFirst();添加

offerLast();


peekFirst();

peekLast();

獲取元素,但不刪除元素。如果集合爲空,返回null。

poolFirst();

poolFirst();

獲取元素,但是元素被刪除。如果集合爲空,返回null。

四、Set集合

(1)、Set概述:

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

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

set集合特點:無序。不能有重複元素。

(2)、Set集合較爲常見的兩個子類HashSet和TreeSet

1、HashSet:底層數據結構是哈希表。

                        HashSet是如何保證元素的唯一性呢?

                       是通過元素的兩個方法,hashcode和equals來完成的。

                       如果元素的hashcode值相同,纔會判斷equals值是否爲true。

                       如果元素的hashcode值不同,猜會調用equals。

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

2、TreeSet:可以對set集合中的元素進行排序

                       底層數據結構是二叉樹,保證了元素的唯一性。compareTo方法return 0 

                       TreeSet排序的第一種方式:讓元素自身具備比較性。元素需要實現comparable接口,覆蓋compareTo方法。

                       這種方式也稱爲元素的自然方式,或者叫默認排序。

程序示例1:TreeSet可以對集合中的元素排序

import java.util.*;

public class TreeSetDemo {
	public static void main(String[] args) {
		TreeSet ts = new TreeSet();
		// TreeSet可以對集合中的元素進行排序
		ts.add("cba");
		ts.add("abcd");
		ts.add("aaa");
		ts.add("bca");

		Iterator it = ts.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}
}

排序的第一種方式:讓元素自身具備比較性,讓元素自身具備比較性。

元素需要實現Compaable接口,覆蓋compareTo方法,這種方式稱爲元素的自然順序,或者叫做默認順序,一被定義出來就具備比較性

程序示例:

/*
 * 存儲之定義對象 往TreeSet集合中存儲自定義對象 想按照學生的年齡進行排序
 */
import java.util.*;

public class Test4 {
	public static void main(String[] args) {
		TreeSet ts = new TreeSet(new MyCompares());
		ts.add(new Student("lisi02", 22));
		ts.add(new Student("lisi007", 20));
		ts.add(new Student("lisi09", 19));
		ts.add(new Student("lisi10", 19));
		ts.add(new Student("lisi007", 20));
		// ts.add(new Student("lise01", 22));
		Iterator it = ts.iterator();
		while (it.hasNext()) {
			Student stu = (Student) it.next();
			System.out.println(stu.getName() + "..." + stu.getAge());

		}
	}
}

class Student implements Comparable {// 該類接口強制讓學生具備比較性
	private String name;
	private int age;

	public int getAge() {
		return age;
	}

	Student(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public int compareTo(Object obj) {
		if (!(obj instanceof Student)) {
			throw new RuntimeException("不是學生對象");
		}
		Student s = (Student) obj;
		// System.out.println(this.name+"...........compareto........"+s.name);
		if (this.age > s.age) {// 此對象大於指定對象返回正數
			return 1;
		} else if (this.age == s.age) {
			return this.name.compareTo(s.name);
		}
		return -1;
	}

}

class MyCompares implements Comparator {
	// 這裏不用複寫equals方法了,因爲MyCompares繼承了Object了。已經有了equals
	public int compare(Object o1, Object o2) {
		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 0; } //return -1;
			 */
			return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
		}
		return num;

	}

}

TreeSet 排序就是互相比較,元素越多,你互相比較的次數越多,效率很低。所以爲了優化效率,TreeSet用了一種特殊的數據結構。二叉樹,減少比較次數,提高比較

性能。(小於的在左邊,大於的在右邊)

如果是降序,return 的值1變爲-1,都取反。

現在讓數據怎麼存進去的怎麼取出來。怎麼做呢?

在TreeSet比較對象的時候,和compareTo 方法中的if判斷是沒有關係的。只看結果,是正是負,是0,?直接return 1就可以實現。

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

在集合初始化時,就有了比較方式。構造函數

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

第一種,讓元素具備比較性,第二種讓容器自身具備比較性。當兩種排序都存在時,以比較器爲主。

定義一個類。實現Comparator接口,覆蓋Compare方法

五、泛型

(1)、概念:泛型是Java SE 1.5的新特性,泛型的本質是參數化類型,也就是說所操作的數據類型被指定爲一個參數。

(2)、好處:

a、將運行時的異常提前至編譯時發生

b、使用get獲取元素的時候無需強類型轉型,就避免了類型轉換的異常問題

(3)、泛型的格式:通過<>來定義要操作的引用數據類型。
(4)、在使用java提供的對象時,什麼時候寫泛型呢?

通常在集合框架中很常見

只要見到<>就要定義泛型。

其實<>就是用來接收類型的。

當使用集合時,將集合中要存儲的數據類型做作爲參數傳遞到<>中即可。

(5)、優化代碼:

/*
 * 存儲之定義對象 往TreeSet集合中存儲自定義對象 想按照學生的年齡進行排序
 */
import java.util.*;

public class Test4 {
	public static void main(String[] args) {
		TreeSet<Student> ts = new TreeSet<Student>(new MyCompares());
		ts.add(new Student("lisi02", 22));
		ts.add(new Student("lisi007", 20));
		ts.add(new Student("lisi09", 19));
		ts.add(new Student("lisi10", 19));
		ts.add(new Student("lisi007", 20));
		// ts.add(new Student("lise01", 22));
		Iterator it = ts.iterator();
		while (it.hasNext()) {
			Student stu = (Student) it.next();
			System.out.println(stu.getName() + "..." + stu.getAge());

		}
	}
}

class Student implements Comparable {// 該類接口強制讓學生具備比較性
	private String name;
	private int age;

	public int getAge() {
		return age;
	}

	Student(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public int compareTo(Object obj) {
		if (!(obj instanceof Student)) {
			throw new RuntimeException("不是學生對象");
		}
		Student s = (Student) obj;
		// System.out.println(this.name+"...........compareto........"+s.name);
		if (this.age > s.age) {// 此對象大於指定對象返回正數
			return 1;
		} else if (this.age == s.age) {
			return this.name.compareTo(s.name);
		}
		return -1;
	}

}

class MyCompares implements Comparator<Student> {// 定義泛型不用轉換了。

	public int compare(Student s1, Student s2) {

		int num = s1.getName().compareTo(s2.getName());
		if (num == 0) {// 主要條件相同,判斷次要條件

			return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
		}
		return num;
	}
}

(6)、自定義泛型

什麼時候定義泛型類呢?

當類中要操作的引用數據類型不確定的時候,早期定義Object來完成擴展。

現在定義泛型來完成擴展。

泛型類定義的泛型,在整個類中有效,如果被方法使用,那麼泛型類的對象明確要操作的具體類型後,所有要操作的類型就已經固定了。

爲了讓不同方法可以操作不同類型,而且類型還不確定,那麼可以就將泛型定義在方法上。

格式:

class Demo{

       public <T> void show(T t)

      {

             syso(t)

      }

}

(7)、靜態方法泛型

靜態方法不可以訪問類上定義的泛型。

如果靜態方法操作的應用數據類型不確定。可以將泛型定義在方法上。

六、Map集合

(1)、Map集合:將鍵映射到值的對象。一個映射不能包含重複的鍵;每個鍵最多隻能映射到一個值。

(2)、常見操作

1、添加:

put(K key, V value) 、、將指定的值與此映射中的指定鍵關聯(可選操作)。

putAll(Map<? extends K,? extends V> m) 、、 從指定映射中將所有映射關係複製到此映射中(可選操作)。

2、刪除:

remove(Object key) 、、如果存在一個鍵的映射關係,則將其從此映射中移除(可選操作)。

clear() 、、從此映射中移除所有映射關係(可選操作)。

3、判斷:

containsValue(Object value)、、如果此映射將一個或多個鍵映射到指定值,則返回 true。

containsKey(Object key)、、如果此映射包含指定鍵的映射關係,則返回 true。

isEmpty()、、 如果此映射未包含鍵-值映射關係,則返回 true。

4、獲取:

get(Object key)、、返回指定鍵所映射的值;如果此映射不包含該鍵的映射關係,則返回 null。

size()、、返回此映射中的鍵-值映射關係數。

value()、、返回此映射中包含的值的 Collection 視圖。

entrySet()、、返回此映射中包含的映射關係的 Set 視圖。

keySet()、、 返回此映射中包含的鍵的 Set 視圖。

import java.util.*;

public class MapDemo {
	public static void main(String[] args) {
		Map<String, String> map = new HashMap<String, String>();

		// 添加元素
		map.put("01", "zhangsan1");
		// map.put("01", "wanger");//當存入元素有相同的鍵值時,後面的添加的值會覆蓋前面的值,並put方法會返回被覆蓋的值

		map.put("02", "zhangsan2");
		map.put("03", "zhangsan3");

		// 判斷,如果此映射包含指定鍵的映射關係,則返回 true。
		System.out.println("containsKey:" + map.containsKey("1"));
		// 刪除,如果存在一個鍵的映射關係,則將其從此映射中移除(可選操作),返回對應的值。如果鍵不存在,返回null
		System.out.println("remove:" + map.remove("01"));
		// 返回指定鍵所映射的值;如果此映射不包含該鍵的映射關係,則返回 null。
		System.out.println("get:" + map.get("02"));

		map.put("04", null);// 可以通過get返回值來判斷一個鍵值是否存在。通過返回空來判斷。這既是HashMap的特點。
		// System.out.println(map.get("04"));

		// 獲取map集合所有的值
		Collection<String> coll = map.values();
		System.out.println(coll);
		System.out.println(map);
	}

}

(3)、Map集合常見子類對象:

Hashtable:底層是哈希表數據結構,不可以存入null鍵null值,該集合是線程同步的,用作鍵的對象,必須實現hashCode方法,和equals方法,該集合是元老級別的。

效率低。jdk1.0。效率較低。

HashMap:底層是哈希表數據結構,並允許使用null鍵null值,該集合不同步的,效率高。idk1.2

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

map集合和set很像,其實set底層就是使用了map集合

(4)、map集合的兩種取出方式:

          1、entrySet()、、返回此映射中包含的映射關係的 Set 視圖。

將map中所有的鍵值都存入到set集合中。因爲set具備迭代器。

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

map集合的取出原理:將map集合轉換成set集合,再根據迭代器取出。

import java.util.*;

public class MapDemo2 {
	public static void main(String[] args) {
		Map<String, String> map = new HashMap<String, String>();

		map.put("02", "張三2");
		map.put("04", "張三4");
		map.put("03", "張三3");
		map.put("01", "張三1");

		// 先獲取map集合所有鍵的set集合,keySet();
		Set<String> keySet = map.keySet();

		// 有了set集合,就可以獲取其迭代器
		Iterator<String> it = keySet.iterator();

		while (it.hasNext()) {
			// 獲取對應的鍵值
			String key = it.next();

			// 有了鍵值,可以通過map集合的get方法,獲取其對應的值
			String value = map.get(key);

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

       2、keySet()、、 返回此映射中包含的鍵的 Set 視圖。

將map集合的對應關係存入到set集合中。

而這個關係的對應的數據類型是:Map.Entry。

import java.util.*;

public class MapDemo3 {
	public static void main(String[] args) {
		Map<String, String> map = new HashMap<String, String>();

		map.put("02", "張三2");
		map.put("04", "張三4");
		map.put("03", "張三3");
		map.put("01", "張三1");

		// 將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);
		}
	}
}

(5)、TreeMap練習

/*練習:“asdfhfdadsebah”獲取該字符串中字母出現的次數。
 * 
 * 希望打印結果:a(1)b(4)c(2)....
 * 
 * 思路:
 * 1.將字符串轉換成數組。因爲要對每一個字母進行操作。
 * 2.定義一個map集合,因爲打印結果的字母有順序,所以用treemap集合
 * 3.遍歷字符數組
 *   將每一個字母作爲鍵去查map集合
 *   如果返回null,將該字母和1存入到map集合中
 *   如果返回不是null,說明該字母已經在map集合存在,並有對應次數
 *   那麼獲取該次數,並進行自增,然後將該字母和自增後的次數存入到map集合中,覆蓋調用原理鍵所對應的值。
 *
 *4.將map集合中的數據轉變成指定的字符串形式返回
 */
import java.util.*;

public class MapTest3 {
	public static void main(String[] args) {
		String s = charCount("asdfhfdadfhdfjdsebah");
		System.out.println(s);
	}

	public static String charCount(String str) {
		char[] chs = str.toCharArray();
		TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>();

		int count = 0;
		for (int x = 0; x < chs.length; x++) {
			Integer value = tm.get(chs[x]);
			if (value != null)
				count = value;
			count++;
			tm.put(chs[x], count);
			count = 0;
			
			/*if (value == null) {
				tm.put(chs[x], 1);
			} else {
				value = value + 1;
				tm.put(chs[x], value);
			}*/
		}
		// System.out.println(tm);

		StringBuilder sb = new StringBuilder();

		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();
			sb.append(ch + "(" + value + ")");
		}

		return sb.toString();
	}

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