Java 集合
主要集合概述
Java 主要有 3 種重要的集合類型:
-
List:是一個有序集合,可以放置重複的元素
-
Set:是一個無序集合,不允許放置重複的元素
-
Map:是一個無序集合,集合中包含一個鍵對象,一個值對象,鍵對象不允許重複,值對象可以重複
- 就像身份證號和姓名 : <鍵 , 值>
集合中只能存儲引用類型,不能存儲基本數據類型
集合中 Collection 的繼承結構圖(重要·背下來)
Collection 中的常用方法
boolean add(E e)
boolean addAll(Collection<? extends E> c)
void clear()
boolean contains(Object o)
boolean containsAll(Collection<?> c)
int hashCode()
boolean isEmpty()
Iterator<E> iterator()
boolean remove(Object o)
boolean removeAll(Collection<?> c)
int size()
Object[] toArray()
-
舉例1
import java.util.*; public class Test02 { public static void main(String[] args) { // 創建集合 Collection c = new ArrayList(); // 添加元素 c.add(1);// auto boxing c.add(new Integer(1)); Object o = new Object(); c.add(o); // 集合中只能單個存儲元素,並且只能存儲引用類行 c.add(new Customer("張三", 23)); // 獲取元素個數 System.out.println(c.size());// 4 // 判斷集合是否爲空 System.out.println(c.isEmpty());// false Object[] resO = c.toArray(); for (int i = 0; i < resO.length; i++) { System.out.println(resO[i]); } // 移除某一個引用 c.remove(1); System.out.println(c.size());//3 // 清空集合 c.clear(); System.out.println(c.size());//0 // 判斷集合是否爲空 System.out.println(c.isEmpty());// true } } class Customer{ String name; int age; public Customer(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Customer [name=" + name + ", age=" + age + "]"; } }
-
舉例2-
Iterator
迭代器Iterator iterator(); 獲取集合所依賴的迭代器對象, 通過迭代器中的方法完成集合的遍歷/迭代
注意: 這種方法是所有集合通用的遍歷方式import java.util.*; /* Iterator iterator(); 獲取集合所依賴的迭代器對象 通過迭代器中的方法完成集合的遍歷/迭代 注意: 這種方法是所有集合通用的遍歷方式 */ public class Test03 { public static void main(String[] args) { // 創建集合對象 Collection c = new LinkedList(); // 添加元素 c.add(122); // 自動裝箱 c.add(false);// 自動裝箱 c.add(399);// 自動裝箱 // 迭代遍歷 // 獲取迭代器對象 // 不需要關心底層集合的具體類型,所有集合依賴的迭代器都實現了 java.util.Iterator; 接口 Iterator iterator = c.iterator(); // 迭代器對象是面向接口編程 // iterator 是引用,保存了內存地址,指向堆中的“迭代器對象” System.out.println(iterator); // java.util.LinkedList$ListItr@15db9742 // 開始調用方法,完成遍歷,迭代 // 原則, 調用 iterator.next() 方法之前必須調用 iterator.hasNext() // while循環 while(iterator.hasNext()) { System.out.println(iterator.next()); } // for 循環 for(Iterator it = c.iterator(); it.hasNext();) { System.out.println(it.next()); } } }
-
舉例3-
contains()
方法contains()底層是調用的equals()方法
注意:自己創建的類一般都要重寫 Object 類中的 equals() 方法,使之用於比較內容
import java.util.*; // boolean contains(Object o) public class Test04 { public static void main(String[] args) { // 創建集合 Collection c = new ArrayList(); // 創建 Integer 類型的對象 Integer i1 = new Integer(256); // 添加元素 c.add(i1); System.out.println(c.contains(256));// true // 創建 Integer 類型的對象 Integer i2 = new Integer(256); // 雖然i2沒有添加進c集合裏面,但是contains()底層是調用的equals()方法 // Integer重寫了Object類中的equals方法 // 所以下面執行結果爲true System.out.println(c.contains(i2));// true Manger m1 = new Manger("張三", 12); c.add(m1); System.out.println(c.contains(m1));// true Manger m2 = new Manger("張三", 12); // Manger類重寫equals方法後 System.out.println(c.contains(m2));// true } } class Manger{ String name; int id; public Manger(String name, int id) { this.name = name; this.id = id; } @Override public boolean equals(Object obj) { if(this == obj) { return true; } if(obj instanceof Manger) { Manger m = (Manger)obj; return this.name == m.name && this.id == m.id; } return false; } }
-
ArrayList 中的contains()方法的實現
public boolean contains(Object o) { return indexOf(o) >= 0; } public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1; }
-
-
舉例4-集合中的
remove()
方法remove() 方法和contains()方法都需要集合中的對象重寫 equals() 方法。 因爲Object類中的equals方法是比較內存地址,而在現實的業務邏輯中不能比較內存地址,該比較內容。
import java.util.*; public class Test05 { public static void main(String[] args) { // 創建集合 Collection c = new ArrayList(); // 添加元素 Integer i1 = new Integer(10); c.add(i1); Integer i2 = new Integer(10); System.out.println(c.remove(i2));// true System.out.println(c.size());// 0 Manger m1 = new Manger("張三", 12); c.add(m1); Manger m2 = new Manger("張三", 12); // Manger類重寫equals方法後 System.out.println(c.remove(m2));// true System.out.println(c.size());//0 } }
-
舉例5-迭代器中的
remove()
方法在使用迭代器循環刪除集合中的元素的時候,不能使用集合的
remove()
方法,只能使用迭代器的remove()
方法import java.util.*; public class Test06 { public static void main(String[] args) { // 創建集合 Collection c = new ArrayList(); c.add(1); c.add(2); c.add(3); // 創建迭代器對象 Iterator it = c.iterator(); while(it.hasNext()) { Object o = it.next(); it.remove();// 使用迭代器刪除 } System.out.println(c.size());// 0 // 如果在迭代的過程中不使用迭代器的 remove()方法 // 使用 集合的 remove()方法可以嗎 // 當然不可以,在第一次循環的時候沒問題,但是第二次循環的時候 it對應的集合已經不是原來的集合了 // 報錯ConcurrentModificationException /* c.add(1); c.add(2); c.add(3); it = c.iterator();// 需要重新指定 it while(it.hasNext()) { Object o = it.next(); c.remove(o);// 使用結合中的方法刪除 // 報錯ConcurrentModificationException } System.out.println(c.size()); // 0 */ } }
List集合詳解
List 是一個接口, 裏面有自己規定的(獨特的)方法
public interface List<E> extends Collection<E>
-
舉例1-List集合中存儲的元素有序且可以重複
import java.util.*; public class Test07 { public static void main(String[] args) { List list = new ArrayList(); list.add(2); list.add(4); list.add(3); list.add(34); // 遍歷 Iterator it = list.iterator(); while(it.hasNext()) { System.out.println(it.next()); } // E get(int index) 獲取對應下標的元素 System.out.println(list.get(3)); } }
-
舉例2-深入
List
集合-
ArrayList集合底層是數組,數組是有下標的,所以ArrayList有很多自己的特性(關於下標的特性)
-
ArrayList集合底層默認初始化數組大小爲 10 ,擴大之後的容量是原容量的 1.5 倍
-
Vector 集合底層默認初始化數組大小爲10,擴大之後的容量是原容量的 2 倍;
如何優化 ArrayLIst 和 Vector?
儘量減少擴容操作,因爲擴容需要數組拷貝。一般推薦在創建集合的時候指定初始化數組的大小
-
方法
void add(int index, E element); Object get(int index); Object remove(int index); Object set(int index, Object element); List subList(int fromIndex, int toIndex)
import java.util.*; public class Test08 { public static void main(String[] args) { List l = new ArrayList(); l.add(23); l.add(123); l.add(321); l.add(69); // 在下標爲 1 的地方添加 555 l.add(1, 555); // 將下標2的地方的數據更改爲 100 l.set(2, 100); // 獲取第1個元素 System.out.println(l.get(0)); System.out.println("======="); // 遍歷(List 集合中特有的遍歷方式) for(int i=0; i<l.size(); i++) { Object o = l.get(i); System.out.println(o); } } }
-
-
Set
對應的類及常用方法
Set 中存儲的元素是無序, 不可重複的,存進去的順序和取出來的順序不一定一致。
HashSet 類實現了Set接口(HashSet 的底層時間上是一個 HashMap,見下圖·java的HashSet源碼)
HashMap底層是哈希表
SortedSet 接口繼承了Set 接口,其存儲的元素也是無需,不可重複的,但是存進去的元素可以按照元素的大小自動排序,TreeSet 類實現了 SortedSet 接口
-
哈希表/散列表(較高的查找/刪除/增加效率)
-
哈希表是數組和單向鏈表的結合
-
哈希表的本質是一個數組,只不過這個數組中的每一個元素都是一個單向鏈表
-
數組中每一個元素存儲的是一個單向鏈表,單向鏈表中每一個節點存儲的是:final int hash, Object key, Object value, Node<> next;
-
hash 值是通過
key
調用hashcode()
方法得到的值,再通過hash
算法得到的值 -
在數組中每一個單向鏈表中節點的hash值都是相同的,代表了數組的下標
-
hashMap中有一個方法用於查找對應的節點:
Object get(Object key)
public V get(Object key) { Node<K,V> e; return (e = getNode(hash(key), key)) == null ? null : e.value; }
-
hashMap中有一個添加元素的方法:
void put(Object key, Object value)
public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; // tab = table if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; // hash 和 數組下標的對應關係:i = (n - 1) & hash if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null);// 新的單向鏈表 else {// 已經存在的單向鏈表 Node<K,V> e; K k; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); else { for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; }
-
-
HashSet
集合詳解
- HashSet實際上是一個HashMap,HashMap底層採用了哈希表數據結構
- HashMap的初始容量是 16,縮放因子是 0.75
- 哈希表又叫散列表。哈希表的底層是一個數組,這個數組的每一個元素是一個單向鏈表,每一個單向鏈表都有一個獨一無二的hash值,代表了數組的下標
- 在一個單向鏈表中每一個節點的hash值是相同的。
- hash值實際上是 key 調用 hashCode 方法,再通過 hash function 得到的值。
- 在一個單向鏈表中每一個節點的hash值是相同的。
- 向hash 表中添加元素的過程:
- 先調用被存儲的
key
的hashCode
方法,經過hash function
得到hash
值- 如果在這個
hash
表中不存在這個hash
值,則直接加入元素。 - 如果該 hash 值已經存在,繼續調用key之間的 equals 方法
- 如果equals方法返回 false,則將該元素田間
- 如果equals方法返回 true,則放棄添加該元素(元素不可重複,所以就不添加了)
- 如果在這個
- 先調用被存儲的
import java.util.*;
public class Test09 {
public static void main(String[] args) {
Set s = new HashSet();
s.add(1);
s.add(1);
s.add(188);
s.add(100);
s.add(74);
s.add(85);
// 遍歷
// 創建迭代器
Iterator it = s.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
// 輸出
1
100
85
74
188
-
關於往
Set
集合裏面添加元素- 存儲在
hashSet
或者HashMap
集合中Key
部分的的元素,需要同時重寫hashCode()
和equals()
方法
import java.util.*; public class Test10 { public static void main(String[] args) { Set s = new HashSet(); Employee e1 = new Employee("1000", "jack"); Employee e2 = new Employee("1000", "jack"); Employee e3 = new Employee("2000", "cook"); Employee e4 = new Employee("2000", "book"); Employee e5 = new Employee("4003", "barabase"); // 添加元素的時候,會先調用Employee裏面的hashCode方法得到hash值,hash不一樣往數組裏面添加 // hash 一樣,調用equals方法,返回false,插入到對應hash單向鏈表中 // 返回 true,不添加,所以要重寫對應類裏面的hashCode()方法和 s.add(e1); s.add(e2); s.add(e3); s.add(e4); s.add(e5); System.out.println(s.size()); } } class Employee{ String no; String name; public Employee(String no, String name) { this.no = no; this.name = name; } // 重寫 Object 中的 hashCode @Override public int hashCode() { return this.no.hashCode();//直接使用 String 類裏面的hashCode方法 } // 重寫 Object中的equals方法 @Override public boolean equals(Object obj) { if(this == obj) { return true; } if(obj instanceof Employee) { Employee e = (Employee)obj; return (this.no == e.no && this.name == e.name); } return false; } }
- 存儲在
SortedSet
接口介紹
-
SortedSet是一個接口
java.util.Set; java.util.SortedSet;//無需不可重複,但是可以按照元素大小自動排序 java.util.TreeSet;
import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; public class Test11 { public static void main(String[] args) throws ParseException { SortedSet ss = new TreeSet(); ss.add(10); ss.add(22); ss.add(12); ss.add(34); ss.add(28); // 遍歷 Iterator it = ss.iterator(); while(it.hasNext()) { System.out.println(it.next()); } /* 輸出 10 12 22 28 34 */ // 字符串 SortedSet strs = new TreeSet(); String s1 = "Jack"; String s2 = "Tom"; String s3 = "Jerry"; String s4 = "Pack"; strs.add(s1); strs.add(s2); strs.add(s3); strs.add(s4); it = strs.iterator(); while(it.hasNext()) { System.out.println(it.next()); } /* 輸出 Jack Jerry Pack Tom */ // 日期 String st1 = "2008-08-08"; String st2 = "2009-08-08"; String st3 = "2008-02-03"; String st4 = "2008-12-14"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date d1 = sdf.parse(st1); Date d2 = sdf.parse(st2); Date d3 = sdf.parse(st3); Date d4 = sdf.parse(st4); SortedSet times = new TreeSet(); times.add(d1); times.add(d2); times.add(d3); times.add(d4); // 遍歷 it = times.iterator(); while(it.hasNext()) { Object o = it.next(); if(o instanceof Date) { Date t = (Date) o; System.out.println(sdf.format(t)); } } /* 輸出 2008-02-03 2008-08-08 2008-12-14 2009-08-08 */ } }
-
Collection 裏面只能存儲引用類型
-
SortedSet裏面存儲的元素不重複,無需,但是會自動根據元素大小來排序
-
爲什麼不同類型的數據(Integer, String, Date)都可以進行比較大小呢?
因爲他們都實現了 Compareable接口,實現了裏面的 compareTo() 方法
-
-
-
SortedSet集合裏面的元素是如何排序的?
在上面的程序中,我們使用了Sun公司已經寫好的Date類/String類型的數據存儲到TreeSet集合中,發現可以直接排序,那麼我們嘗試以下往SortedSet中存儲我們自己寫的類會發生什麼呢?
import java.util.*; public class Test12 { public static void main(String[] args) { SortedSet ss = new TreeSet(); User u1 = new User(10); User u2 = new User(13); User u3 = new User(12); User u4 = new User(15); User u5 = new User(11); ss.add(u1); ss.add(u2); ss.add(u3); ss.add(u4); ss.add(u5); Iterator it = ss.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } } class User{ int age; public User(int age) { this.age = age; } @Override public String toString() { return "User[age="+this.age+"]"; } }
// 編譯成功,運行錯誤 Exception in thread "main" java.lang.ClassCastException: com.test.collections.User cannot be cast to java.lang.Comparable at java.util.TreeMap.compare(Unknown Source) at java.util.TreeMap.put(Unknown Source) at java.util.TreeSet.add(Unknown Source) at com.test.collections.Test12.main(Test12.java:11)
運行報 “類型轉換錯誤” 的錯誤, 我們自己寫的類不能轉換成
java.lang.Comparable
類型,所以我們應該實現Comparable
接口裏面的方法所以說 凡是放在
SortedSet
裏面的元素 必須 實現了Comparable
接口裏面的compareTo()
方法。import java.util.*; public class Test12 { public static void main(String[] args) { SortedSet ss = new TreeSet(); User u1 = new User(10); User u2 = new User(13); User u3 = new User(12); User u4 = new User(15); User u5 = new User(11); ss.add(u1); ss.add(u2); ss.add(u3); ss.add(u4); ss.add(u5); Iterator it = ss.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } } class User implements Comparable{// 繼承Comparable接口實現裏面的方法 int age; public User(int age) { this.age = age; } @Override public String toString() { return "User[age="+this.age+"]"; } // 實現Comparable 接口中的 compareTo方法 @Override public int compareTo(Object o) { return this.age-((User)o).age; } }
這樣就可以成功運行了,輸出結構是按照年齡從小到大排序的
User[age=10] User[age=11] User[age=12] User[age=13] User[age=15]
-
讓
SortedSet
集合做到排序還有另一種方式:java.util.Comparator
- 單獨編寫一個比較器,傳入到
TreeSet
對象中。 - 比較推薦此類寫法,因爲不需要改變存入
SortedSet
內元素的類,具有更低的耦合性
import java.util.*; public class Test13 { public static void main(String[] args) { @SuppressWarnings("unchecked") SortedSet ss = new TreeSet(new ProductComparator()); Product p1 = new Product(32); Product p2 = new Product(12); Product p3 = new Product(24); Product p4 = new Product(13); ss.add(p1); ss.add(p2); ss.add(p3); ss.add(p4); // 遍歷 Iterator it = ss.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } } class Product{ double price; public Product(double price) { this.price = price; } @Override public String toString() { return "Product["+this.price+"]"; } } class ProductComparator implements Comparator{ @Override public int compare(Object o1, Object o2) { if(o1 instanceof Product && o2 instanceof Product) { double price1 = ((Product)o1).price; double price2 = ((Product)o2).price; if(price1 == price2) { return 0; }else if(price1 > price2) { return 1; }else { return -1; } } return 0; } }
也可以使用匿名內部類
import java.util.*; public class Test13 { public static void main(String[] args) { @SuppressWarnings("unchecked") SortedSet ss = new TreeSet(new Comparator() {// 匿名內部類 @Override public int compare(Object o1, Object o2) { double price1 = ((Product)o1).price; double price2 = ((Product)o2).price; if(price1 == price2) { return 0; }else if(price1 > price2) { return 1; }else { return -1; } } }); Product p1 = new Product(32); Product p2 = new Product(12); Product p3 = new Product(24); Product p4 = new Product(13); ss.add(p1); ss.add(p2); ss.add(p3); ss.add(p4); // 遍歷 Iterator it = ss.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } } class Product{ double price; public Product(double price) { this.price = price; } @Override public String toString() { return "Product["+this.price+"]"; } }
輸出結果:// 已經排序了
Product[12.0] Product[13.0] Product[24.0] Product[32.0]
- 單獨編寫一個比較器,傳入到
集合中 Map
的繼承結構圖(重要)
Map
和Collection
沒有關係
-
Map
是一個父接口,HashMap
類和Hashtable
類實現了Map
接口,SortedMap
接口繼承Map
接口,TreeMap
類實現了SortedMap
接口 -
HashMap
中的key
要重寫hashCode()
和equals()
方法 -
SortedMap
或者TreeMap
的key
要實現Comparable
接口中的compareTo()
方法。或者單獨寫一個Comparator
比較器 -
Properties
類繼承自Hashtable
,是一個屬性類,也是以key-value
的方式存儲元素,但是key-value
只能是字符串
Map集合中常用的方法
- 存儲在
Map
集合中的key
部分的元素需要同時重寫hashCode()
和equals()
方法。
void clear();
boolean isEmpty();
int size();
V get(Object key);
V put(K key, V value); // 注意:map中如果key重複了,value將會覆蓋key對應的值
boolean containsKey(Object key);
boolean containsValue(Object value);
V remove(Object key);
Set keySet();
Collection values();
Set entrySet()
import java.util.*;
public class Test14 {
public static void main(String[] args) {
// 1.創建集合
Map persons = new HashMap();
// 2. 存儲鍵值對
persons.put("10000", "Javk");
persons.put("10001", "Cook");
persons.put("10002", "Book");
persons.put("10003", "Kook");
persons.put("10004", "Pook");
persons.put("10002", "BooJ");
// 3. 判斷鍵值對的個數
// Map 中的key是無序的不可重複的
System.out.println(persons.size());// 5
// 4. 判斷Map中是否包含某key
System.out.println(persons.containsKey("10003"));// true
// 5. 判斷Map中是否包含某value
System.out.println(persons.containsValue("Javk"));// true
System.out.println(persons.containsValue("Book"));// false
// 6. 通過 key 獲取value
String key = "10002";
Object value = persons.get(key);
System.out.println(value);// BooJ // BooJ將Book覆蓋掉了
// 7. 通過key刪除鍵值對
persons.remove("10004");
System.out.println(persons.size());// 4
// 8. 獲取所有的value
Collection values = persons.values();
Iterator it = values.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
// 9. 獲取所有的 key
Set keys = persons.keySet();
it = keys.iterator();
while(it.hasNext()) {
Object id = it.next();
Object name = persons.get(id);
System.out.println(id+"-->"+name);
}
// 10. entrySet
Set entrySet = persons.entrySet();
it = entrySet.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
Hashtable
& Properties
常用方法介紹
-
Hashtable
是線程安全的,但是效率低- 初始化容量是 11, 加載因子是 0.75
HashMap
的初始化容量是 16, 加載因子是 0.75
-
Properties
是一個屬性類,繼承自Hashtable
類,存儲的key-value
只能是字符串import java.util.*; public class Test15 { public static void main(String[] args) { // 1.創建屬性類對象 Properties p = new Properties(); // 2. 存儲元素 p.setProperty("driver", "oracle.jdbc.driver.OracleDriver"); p.setProperty("username", "tailor"); // 注意 key 不能重複,如果重複則覆蓋原來的value p.setProperty("username", "tailor95"); p.setProperty("password", "balabala"); p.setProperty("url", "jdbc:oracle:thin:@192.168.1.100:1512:balabala"); // 3. 通過 key 獲取 value String v1 = p.getProperty("driver"); String v2 = p.getProperty("username"); String v3 = p.getProperty("password"); String v4 = p.getProperty("url"); System.out.println(v1); System.out.println(v2); System.out.println(v3); System.out.println(v4); } }
輸出:
oracle.jdbc.driver.OracleDriver tailor95 balabala jdbc:oracle:thin:@192.168.1.100:1512:balabala
SortedMap
& TreeMap
-
SortedMap
中key
的特點:無序不重複,但是存進去的元素可以按照大小自動排序- 如果想自動排序,
key
部分的元素需要:或者實現Comparable
接口, 或者單獨實現一個比較器Comparator
- 下面代碼是 實現了
Comparable
接口
- 下面代碼是 實現了
import java.util.*; public class Test16 { public static void main(String[] args) { // Map 中的key 存儲 product, value存儲 重量 // 1. 創建 map集合 SortedMap sm = new TreeMap(); // 2. 準備 對象 ProductMap p1 = new ProductMap("西瓜", 0.5); ProductMap p2 = new ProductMap("蘋果", 3.0); ProductMap p3 = new ProductMap("香蕉", 2.0); ProductMap p4 = new ProductMap("橘子", 1.5); // 3. 添加到map中 sm.put(p1, 8.0); sm.put(p2, 5.0); sm.put(p3, 2.0); sm.put(p4, 3.0); // 4. 遍歷 Iterator it = sm.keySet().iterator(); while(it.hasNext()) { Object p = it.next(); Object w = sm.get(p); System.out.println(p+"===>"+w); } } } class ProductMap implements Comparable{// 實現 Comparable接口 String name; double price; public ProductMap(String name, double price) { this.name = name; this.price = price; } // 重寫 toString @Override public String toString() { return "[Product:"+this.name+"--->"+this.price+"]"; } @Override public int compareTo(Object o) { double price1 = this.price; double price2 = ((ProductMap)o).price; if(price1 > price2) { return 1; }else if(price1 < price2) { return -1; }else return 0; } }
-
下面代碼是單獨實現了一個比較器
Comparator
(使用了匿名內部類)package com.test.collections; import java.util.*; public class Test16 { public static void main(String[] args) { // Map 中的key 存儲 product, value存儲 重量 // 1. 創建 map集合 // SortedMap sm = new TreeMap(); SortedMap sm = new TreeMap(new Comparator() {// 單獨實現了一個比較器 @Override public int compare(Object o1, Object o2) { double price1 = ((ProductMap)o1).price; double price2 = ((ProductMap)o2).price; if(price1 > price2) { return 1; }else if(price1 < price2) { return -1; }else return 0; } }); // 2. 準備 對象 ProductMap p1 = new ProductMap("西瓜", 0.5); ProductMap p2 = new ProductMap("蘋果", 3.0); ProductMap p3 = new ProductMap("香蕉", 2.0); ProductMap p4 = new ProductMap("橘子", 1.5); // 3. 添加到map中 sm.put(p1, 8.0); sm.put(p2, 5.0); sm.put(p3, 2.0); sm.put(p4, 3.0); // 4. 遍歷 Iterator it = sm.keySet().iterator(); while(it.hasNext()) { Object p = it.next(); Object w = sm.get(p); System.out.println(p+"===>"+w); } } } class ProductMap{ String name; double price; public ProductMap(String name, double price) { this.name = name; this.price = price; } // 重寫 toString @Override public String toString() { return "[Product:"+this.name+"--->"+this.price+"]"; } }
輸出:可見key按照價格排了序
[Product:西瓜--->0.5]===>8.0 [Product:橘子--->1.5]===>3.0 [Product:香蕉--->2.0]===>2.0 [Product:蘋果--->3.0]===>5.0
- 如果想自動排序,
關於集合工具類Collections
的用法
-
java.util.Collections
是一個類,是集合的工具類,可以實現對集合的操作-
java.util.Collection
是一個接口 -
Collections
裏面的sort
方法,實現集合內的元素的排序static void sort(List list)
-
示例1
import java.util.*; public class Test17 { public static void main(String[] args) { // 1. 創建List集合 List l = new ArrayList(); // 2. 添加元素 l.add(10); l.add(20); l.add(14); l.add(23); // 3. 遍歷 for(int i=0; i<l.size(); i++) { System.out.println(l.get(i)); } // 調用 Collcetions類中的 sort方法排序 Collections.sort(l); // 遍歷 System.out.println("========="); for(Iterator it = l.iterator();it.hasNext();) { System.out.println(it.next()); } } }
輸出:
10 20 14 23 ========= 10 14 20 23
-
Collcetions
類中的sort()
方法怎麼對集合中的元素進行排序?- 將
Set
集合轉換爲List
類型
import java.util.*; public class Test18 { public static void main(String[] args) { // 1. 創建set集合 Set s = new HashSet(); // 2. 添加元素 s.add(12); s.add(10); s.add(21); s.add(32); // 3. 創建List###########就是在這操作的############### List list = new ArrayList(s); // 4. 調用Collections工具類中的sort()方法進行排序 Collections.sort(list); // 5. 遍歷 Iterator it = list.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } }
- 將
-
是不是
List
中存儲的所有類型的元素都可以調用Collections
類中的sort
方法?- 當然不是,元素要麼實現
Comparable
接口,要麼單獨寫一個比較器Comparator
- 下面代碼運行錯誤:
java.lang.ClassCastException: Person cannot be cast to java.lang.Comparable
- 需要實現
Comparable
接口
- 需要實現
- 下面代碼運行錯誤:
import java.util.*; public class Test19 { public static void main(String[] args) { // 創建集合 List list = new ArrayList(); // 準備數據 Person p1 = new Person(); Person p2 = new Person(); Person p3 = new Person(); Person p4 = new Person(); // 添加數據 list.add(p1); list.add(p2); list.add(p3); list.add(p4); // 調用Collections類中的sort方法 Collections.sort(list); // 遍歷輸出 Iterator it = list.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } } class Person{ // 沒有實現 Comparable }
-
實現
Comparable
接口package com.test.collections; import java.util.*; public class Test19 { public static void main(String[] args) { // 創建集合 List list = new ArrayList(); // 準備數據 Person p1 = new Person(); Person p2 = new Person(); Person p3 = new Person(); Person p4 = new Person(); // 添加數據 list.add(p1); list.add(p2); list.add(p3); list.add(p4); // 調用Collections類中的sort方法 Collections.sort(list); // 遍歷輸出 Iterator it = list.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } } class Person implements Comparable{ @Override public int compareTo(Object o) { return 0; } }
- 當然不是,元素要麼實現
-
Collections
類中的synchronizedList(List list)
方法可以將線程不安全的ArrayList
轉換成線程安全的import java.util.*; public class Test20 { public static void main(String[] args) { List list = new ArrayList(); Collections.synchronizedList(list); // 這之後,list就是線程安全的了 } }
-
泛型初步
主要介紹jdk5.0
的新特性: 泛型(屬於編譯期的概念)
爲什麼引入泛型
- 可以統一集合中的數據類型
- 可以減少強制類型轉換
泛型語法如何實現
-
泛型是編譯階段的語法,在編譯階段統一集合中的數據類型
List
使用泛型
import java.util.*; public class Test21 { public static void main(String[] args) { // 創建泛型集合// 創建String類型的集合 List<String> list = new ArrayList<String>(); // 添加元素 //list.add(1);// 編譯錯誤 list中存儲的是String類型,所以不能添加 Integer 類型的數據 list.add("Jack"); list.add("Tom"); list.add("Jerry"); list.add("Snobe"); // 遍歷泛型集合 Iterator<String> it = list.iterator(); while(it.hasNext()) { String s = it.next(); System.out.println(s); } } }
-
Map
使用泛型import java.util.*; public class Test22 { public static void main(String[] args) { // 創建集合 Map<String, Integer> maps = new HashMap<String, Integer>(); // 添加元素 maps.put("蘋果", 23); maps.put("橘子", 18); maps.put("香蕉", 3); maps.put("西瓜", 64); // 遍歷 // 得到所有的key Set<String> keys = maps.keySet(); Iterator<String> it = keys.iterator(); while(it.hasNext()) { String key = it.next(); Integer i = maps.get(key); System.out.println(key+"--->"+i); } } }
-
SortedSet
使用泛型- 注意實現
Comparable
接口
import java.util.*; public class Test23 { public static void main(String[] args) { // 創建集合 SortedSet<Manager> ss = new TreeSet<Manager>(); // 準備數據 Manager m1 = new Manager(23.0); Manager m2 = new Manager(22.0); Manager m3 = new Manager(23.4); Manager m4 = new Manager(12.0); Manager m5 = new Manager(18.5); ss.add(m1); ss.add(m2); ss.add(m3); ss.add(m4); ss.add(m5); // 遍歷數據 Iterator<Manager> it = ss.iterator(); while(it.hasNext()) { it.next().work(); } } } class Manager implements Comparable<Manager>{ // 實現 Comparable接口 double sal; public Manager(double sal) { this.sal = sal; } public void work() { System.out.println("工作,一個月"+sal+"元"); } @Override public String toString() { return sal+""; } @Override public int compareTo(Manager o) { if(this.sal > o.sal) { return 1; }else if(this.sal < o.sal) { return -1; } return 0; } }
- 注意實現
自定義泛型
public class Test24 {
public static void main(String[] args) {
MyClass<String> mc = new MyClass<String>();
// mc.m1(100);// 編譯錯誤
mc.m1("Jack");;
}
}
class MyClass<T>{
void m1(T t) {
System.out.println(t);
}
}
泛型的優點和缺點
- 優點:同一類型,減少強制轉換
- 缺點:只能存儲一種類型
forEach
關於增強 for
循環(JDK5.0
新特性)
語法:
for(類型 變量:數組名/集合名){}
-
集合如果想使用 **增強
for
**循環這種語法,集合需要使用 泛型- 不使用泛型也可以,但是
for
裏面的變量類型應該是Object
import java.util.*; public class Test25 { public static void main(String[] args) { int[] a= {1,2,3,4}; for(int e: a) { System.out.println(e); } System.out.println("=========="); // 集合 Set<String> s = new HashSet<String>(); s.add("張三"); s.add("李四"); s.add("王五"); s.add("趙六"); // 遍歷 for(String name:s) { System.out.println(name); } } }
- 不使用泛型也可以,但是
-
增強
for
循環的缺點:- 沒有下標
end