一、集合概論
(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集合
List本身也是一個抽取出來的接口Collection:
|--List:元素是有序的,元素可以重複,因爲該集合體繫有索引
|--Set :元素無序,元素不可以重複
(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特有的方法
如果集合爲空,會出現NoSuchElementException異常。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); } }
在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)、好處:
(3)、泛型的格式:通過<>來定義要操作的引用數據類型。a、將運行時的異常提前至編譯時發生
b、使用get獲取元素的時候無需強類型轉型,就避免了類型轉換的異常問題
(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(); } }