集合框架概述
- 集合類的作用:存儲對象,長度可變。
- 所屬的包:java.util
- 集合框架常用體系
Collection
|---List(有序):通過重寫equals()保證唯一性。
|---ArrayList(變長數組):查詢效率高,更新效率低。線程不同步
|---LinkedList(鏈表):更新效率高,查詢效率低。
|---Vector(數組):線程同步,效率低,被ArrayList取代。
|---Set(唯一)
|---HashSet(哈希表):重寫hashCode()和equals()保證唯一性。
|---TreeSet(二叉樹):通過讓元素具備比較性或讓集合具備比較性保證唯一性和排序。
Map
|---HashMap(哈希表):允許使用null鍵null值,線程不同步,效率高。
|---TreeMap(二叉樹):可以按鍵排序,不同步。
|---HashTable(二叉樹):不允許使用null鍵null值,線程同步,效率低。
- 如何選擇具體的集合類?
- 要求時間複雜度:List
- 查詢操作多:ArrayList
- 更新操作多:LinkedList
- 要求空間複雜度:Set
- 只要求唯一性:HashSet
- 要求唯一、有序:TreeSet
- 要求時間複雜度:List
Collection接口
共性方法(關於集合)
- 增:add(Object)
- 刪:remove(Object)、clear()
- 查:size()、contains(Object)、isEmpty()
- 並:addAll(Collection)
- 交:retainAll(Collection)
- 差:removeAll(Collection)
Iterator迭代器
- 爲什麼出現迭代器?
由於Collection子接口下有的有索引有的沒索引,不能像數組循環一樣獲取元素,因此必須有hasNext()和next(),兩個方法只有一起使用時纔有意義,因此將其封裝成Collection的內部類,修飾爲private並對外提供獲取內部類對象的接口iterator(),返回類型是Iterator。比喻:Collection接口是娃娃機,Iterator是娃娃機的夾子,娃娃機夾子有抓取娃娃的操縱桿next()。
迭代器示例
Iterator it = al.iterator(); while(it.hasNext()) { sop(it.next()); }
注意
在迭代時不可以通過集合對象的方法操作集合中的元素,因爲會發生併發修改異常,所以只能通過迭代器的方法操作元素。
- 爲什麼出現迭代器?
List接口
- List特有方法(關於索引)
增:add(index,ele)、addAll(index,Collection)
刪:remove(index)
改:set(index,ele)
查:get(index)、indexOf(ele)、subList(from,to)、listIterator()
ListIterator迭代器
ListIterator相較於Iterator迭代器的作用:由於List集合有索引,因此可在迭代的同時使用ListIterator迭代器的增刪改查方法對元素進行操作。方法:add(ele)、remove()、set(ele)、hasNext()、hasPrivious()。
ListIterator li = al.listIterator(); while(li.hasNext()) { Object obj = li.next(); if(obj.equals("haha")) li.add("hehe"); //利用迭代器進行集合的添加元素 }
LinkedList特有方法(關於收尾結點)
1.增:addFirst()、addLast()、 2.刪:removeFirst()、removeLast() 3.查:getFirst()、getLast() 若集合中沒有元素,會出現NoSuchElementException異常 JDK1.6出現的替代方法 1.增:offerFirst()、offerFirst() 2.刪:peakFirst()、peakLast() 3.查:pollFirst()、pollLast() 若集合中沒有元素,會返回null。
- List特有方法(關於索引)
Set接口
HashSet保證唯一性依據:hashCode和equals()。先比較兩個對象的hashCode是否相同,若不同,直接存儲進集合;若相同,再用equals()比較是否是同一個對象,若不是就存儲進集合,否則不存儲。代碼示例。
import java.util.*; class Person { private String name; private int age; Person(String name,int age) { this.name = name; this.age = age; } //重寫hashCode() public int hashCode() { return name.hashCode()+age; } //重寫equals() public boolean equals(Object obj) { if(!(obj instanceof Person)) return false; Person p = (Person)obj; return name.equals(p.name) && age == p.age; } public String getName() { return name; } public int getAge() { return age; } } class HashSetDemo { public static void main(String[] args) { HashSet hs = new HashSet(); hs.add(new Person("a1",11)); hs.add(new Person("a2",12)); hs.add(new Person("a2",12)); //重複元素 hs.add(new Person("a3",13)); for(Iterator it = hs.iterator();it.hasNext();) { Person p = (Person)it.next(); System.out.println(p.getName()+":"+p.getAge()); } } }
TreeSet可實現元素排序,排序的兩種方式
- 讓元素自身具備比較性:實現Comparable,重寫compareTo(),使元素實現自然排序。
- 讓集合具備比較性:自定義比較器類,實現Comparator接口,重寫compare(),傳自定義比較器類的對象給集合的構造函數,讓集合排序。應用場景:當使用別人的類,但比較性不是自己需要的時候。
//第一種排序方式:讓元素自身具備比較性,實現自然排序 import java.util.*; class Person implements Comparable { private String name; private int age; Person(String name,int age) { this.name = name; this.age = age; } //重寫compareTo方法 public int compareTo(Object obj) { if(!(obj instanceof Person)) throw new RuntimeException("不是人對象"); Person p = (Person)obj; if(this.age > p.age) return 1; if(this.age == p.age) //若主要依據相同,要比較次要依據 return this.name.compareTo(p.name); return -1; } public String getName() { return name; } public int getAge() { return age; } } class TreeSetDemo { public static void main(String[] args) { TreeSet ts = new TreeSet(); ts.add(new Person("lisi01",22)); ts.add(new Person("lisi02",25)); ts.add(new Person("lisi03",22)); ts.add(new Person("lisi03",22)); //重複元素 ts.add(new Person("lisi04",23)); for(Iterator it = ts.iterator();it.hasNext();) { Person p = (Person)it.next(); System.out.println(p.getName()+":"+p.getAge()); } } }
//第二種排序方式:讓集合具備比較性 import java.util.*; class MyComparator implements Comparator { //重寫compare方法 public int compare(Object o1,Object o2) { Person p1 = (Person)o1; Person p2 = (Person)o2; int num = p1.getName().compareTo(p2.getName()); if(num == 0) //若主要依據相同,要比較次要依據 return new Integer(p1.getAge()).compareTo(new Integer(p2.getAge())); return num; } } class TreeSetDemo1 { public static void main(String[] args) { //傳入比較器對象使集合具備比較性 TreeSet ts = new TreeSet(new MyComparator()); ts.add(new Person("lisi01",22)); ts.add(new Person("lisi02",25)); ts.add(new Person("lisi03",22)); ts.add(new Person("lisi03",22)); //重複元素 ts.add(new Person("lisi04",23)); for(Iterator it = ts.iterator();it.hasNext();) { Person p = (Person)it.next(); System.out.println(p.getName()+":"+p.getAge()); } } }
泛型
作用
- 將運行時期出現的問題ClassCastException轉移到了編譯時期,方便於程序員解決問題。
- 避免了強制轉換麻煩。
- 一般在集合類中使用。
import java.util.*; class GenericDemo { public static void main(String[] args) { //定義時就明確了要操作的類型 ArrayList<String> al = new ArrayList<String>(); //只能操作String類型 al.add("abc01"); al.add("abc02"); al.add("abc03"); for(Iterator<String> it = al.iterator();it.hasNext();) { String s = it.next(); System.out.println(s); } } }
泛型類
使用場景:當類的對象要操作的類型一確定,成員方法操作的類型就明確,就可定義泛型類。
/* //泛型前做法 class Tool { private Object obj; public void setObject(Object obj) { this.obj = obj; } public Object getObject() { return obj; } } */ //泛型類 class Utils<T> { private T t; public void setObject(T t) { this.t = t; } public T getObject() { return t; } } class GenericDemo2 { public static void main(String[] args) { //泛型前做法 // Tool t = new Tool(); // t.setObject(new String("abc")); // String s = (String)t.getObject(); //需要轉型 // System.out.println(s); //泛型做法 Utils<String> u = new Utils<String>(); u.setObject(new String("abc")); String s = u.getObject(); //無需轉型 System.out.println(s); } }
泛型方法
使用場景:爲了讓類中的不同方法可以操作不同類型,就可以將泛型定義在法上,類似於重載。
class Demo<T> { public void show(T t) //跟隨類的泛s型 { System.out.println("show:"+t); } public <Q> void print(Q q) //方法上的泛型 { System.out.println("print:"+q); } } class GenericDemo3 { public static void main(String[] args) { Demo<Integer> d = new Demo<Integer>(); //指定操作的類型是Integer d.show(new Integer(3)); //d.show("abc"); //編譯出錯,show()參數類型只能是Integer d.print(3); //print()參數類型任意 d.print("abc"); } }
靜態方法的泛型只能定義在方法上,因爲靜態比對象先加載。
泛型限定
1. 泛型的限定:? 通配符,代表任意類型 2. 泛型限定上限:<? extends E> 接收E或者E的子類型 3. 泛型限定下限:<? super E>> 接收E或者E的父類型
//泛型限定上限 import java.util.*; class GenericDemo4 { public static void main(String[] args) { TreeSet<Person> ts = new TreeSet<Person>(new Comp()); ts.add(new Person("lisi1")); ts.add(new Person("lisi2")); ts.add(new Person("lisi3")); TreeSet<Student> ts1 = new TreeSet<Student>(new Comp()); ts1.add(new Student("zhang1")); ts1.add(new Student("zhang2")); ts1.add(new Student("zhang3")); print(ts); print(ts1); } //泛型限定,只可以接收Person及其子類對象 public static void print(TreeSet<? extends Person> al) { for(Iterator<? extends Person> it = al.iterator();it.hasNext();) { //只能調用父類中的方法 System.out.println(it.next().getName()); //it.next().showName(); //編譯出錯,無法使用子類特有方法 } } } class Person { private String name; Person(String name) { this.name = name; } public String getName() { return name; } } class Student extends Person { Student(String name) { super(name); } public void showName() { System.out.println(getName()); } } //比較器泛型使用,可以比較Person和Person子類 class Comp implements Comparator<Person> { public int compare(Person p1,Person p2) { //只能用父類方法 return p1.getName().compareTo(p2.getName()); } }
//泛型限定下限 import java.util.*; import stu.love.v.Demo11; //父類的比較器 <Person> class CompareByAge implements Comparator<Person> { public int compare(Person s1,Person s2) { int num = new Integer(s1.getAge()).compareTo(new Integer(s2.getAge())); if(num==0) return s1.getName().compareTo(s2.getName()); return num; } } /*// 子類 特殊的 比較器 Student class ComByAge implements Comparator<Student> { public int compare(Student s1,Student s2) { int num = new Integer(s1.getAge()).compareTo(new Integer(s2.getAge())); if(num==0) return s1.getName().compareTo(s2.getName()); return num; } } // 子類 特殊的 比較器 Teacher class ComByAge2 implements Comparator<Teacher> { public int compare(Teacher s1,Teacher s2) { int num = new Integer(s1.getAge()).compareTo(new Integer(s2.getAge())); if(num==0) return s1.getName().compareTo(s2.getName()); return num; } }*/ class Demo13 { //TreeSet<E>(Comparator<? super E> comparator) 定義比較器時,可以是E類型,還可以是E的父類型,E在創建集合對象時確定 public static void main(String[] args) { TreeSet<Student> t1 = new TreeSet<Student>(new CompareByAge()); t1.add(new Student("zhaosi",23)); t1.add(new Student("lisi",25)); t1.add(new Student("wangwu",20)); TreeSet<Teacher> t2 = new TreeSet<Teacher>(new CompareByAge()); t2.add(new Teacher("wang",38)); t2.add(new Teacher("lilaoshi",48)); t2.add(new Teacher("zhanglaoshi",58)); } }
Map接口
- 描述
存儲鍵值對,一個鍵對應一個值,當後添加的鍵與之前的鍵相同時,後添加的元素會覆蓋之前的元素。
- 方法
增:put(key,value)、putAll(Map)
刪:remove(key)、clear()
獲取:size()、get(key)、values()、entrySet()、keySet()
判斷:isEmpty()、containsKey(key)、containsValue(value)
獲取元素的兩種方式:keySet和entrySet()
- keySet():獲取Map集合的鍵集合
- entrySet():獲取Map集合的映射關係集合
//keySet()和entrySet()用法案例 import java.util.*; class MapDemo2 { public static void main(String[] args) { Map<String,String> map = new HashMap<String,String>(); map.put("02","lisi2"); map.put("01","lisi1"); map.put("03","lisi3"); map.put("04","lisi4"); //1,通過keySet獲取鍵的集合 Set<String> keySet = map.keySet(); for(Iterator<String> it = keySet.iterator();it.hasNext();) { //取出一個鍵 String key = it.next(); //通過鍵獲取值 System.out.println(key+":"+map.get(key)); } //2,通過entrySet獲取映射關係集合 Set<Map.Entry<String,String>> entrySet = map.entrySet(); for(Iterator<Map.Entry<String,String>> it1 = entrySet.iterator();it1.hasNext();) { //取出一個映射關係 Map.Entry<String,String> me = it1.next(); //通過映射關係獲取鍵 String key = me.getKey(); //通過映射關係獲取值 String value = me.getValue(); System.out.println(key+":"+value); } } }
/* Map集合一鍵一值用例 "yure" Student("01","zhangsan") "yure" Stduent("02","lisi") "jiuye" Student("01" "wangwu") "jiuye" Student("02" "zhaoliu") 即一對多關係,由於Map是一對一關係,後會覆蓋前, 因此要將一對多化解爲一對一:將值存儲在集合中。 */ import java.util.*; class MapDemo5 { public static void main(String[] args) { //預熱班 List<Student> yure = new ArrayList<Student>(); yure.add(new Student("01","zhangsan")); yure.add(new Student("02","lisi")); //就業班 List<Student> jiuye = new ArrayList<Student>(); jiuye.add(new Student("01","wangwu")); jiuye.add(new Student("02","zhaoliu")); //學校 HashMap<String,List<Student>> czbk = new HashMap<String,List<Student>>(); czbk.put("yure",yure); //學校有預熱班和就業班 czbk.put("jiuye",jiuye); //遍歷czbk集合,獲取所有教室 for(Iterator<String> it = czbk.keySet().iterator();it.hasNext();) { String roomName = it.next(); //獲取一個鍵(教室名稱) List<Student> room = czbk.get(roomName); //通過教室名稱獲取學生集合 System.out.println(roomName); getInfos(room); //輸出每個學生的信息 } } //遍歷list集合中每個學生的信息 public static void getInfos(List<Student> list) { for(Iterator<Student> it = list.iterator();it.hasNext();) { System.out.println(it.next()); } } } class Student { private String id; private String name; Student(String id,String name) { this.id = id; this.name = name; } public String toString() { return id+name; } }
Collections 工具類
作用:由於List集合不能排序,Collections工具類提供了對List集合進行排序的方法和其他對集合進行操作的方法。