黑馬程式設計師-集合-Set和Map和Collections
第一講 Set
1. Set介面的概述
不包含重複的元素,無序(儲存和取出的順序不一樣)。和collection的功能是一樣的,無特殊。
|--HashSet: HashSet底層資料結構是雜湊表,保證元素唯一性的原理是:判斷元素的hashCode()是否相同,相同就判斷equalis()方法是否為true;不保證Set的迭代順序。
|--TreeSet: TreeSet 底層是二叉樹結構,元素是唯一,有序的(按照某種規則排序)
2. HashSet
HashSet中和元素唯一性相關的操作都依賴於hashCode()和euqals()方法
如add()方法的原始碼可知
步驟:比較雜湊值
相同:比較地址值或equals()
相同:不新增
不同:新增到集合中
不同:新增到集合中
注意:String重寫了hashCode()和equals()方法,所以內容相同的會直接去掉
示例:HashSet儲存自定義物件並遍歷
//先是宣告一個學生類Student.java,兩個成員變數,名字和年齡 public class Student { private String name; private int age; public Student() { super(); } public Student(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } //重寫hashCode和equals @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name ==null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } }
在HashSetDemo.java中遍歷
public class HashSetDemo{ public static void main(String[] args) { // 建立集合物件 HashSet<Student> hs = new HashSet<Student>(); // 建立學生物件 Student s1 = new Student("林青霞", 27); Student s2 = new Student("柳巖", 22); Student s3 = new Student("王祖賢", 30); Student s4 = new Student("林青霞", 27); Student s5 = new Student("林青霞", 20); Student s6 = new Student("范冰冰", 22); // 新增元素 hs.add(s1); hs.add(s2); hs.add(s3); hs.add(s4); hs.add(s5); hs.add(s6); // 遍歷集合 for (Student s : hs) { System.out.println(s.getName() + "---" + s.getAge()); } } }
3. TreeSet
TreeSet的特點是唯一,有序的,有序是指讓元素按照某種規則排序
規則分為兩種,自然排序和比較器排序。
TreeSet的底層是依賴於二叉樹中的紅黑樹
3.1 紅黑樹---一種自平衡的二叉查詢樹
3.2 TreeSet的排序規則—自然排序
自然排序是讓元素本身具備比較性,所比較的元素的類實現實現Comparable介面,覆蓋compareTo()方法。
如果返回值為0,則表示此物件等於指定物件,所以排序後儲存其中之一
返回值為正數,則此物件大於指定物件;返回值為負數,則此物件小於指定物件
Student.java
/*
* 如果一個類的元素要想能夠進行自然排序,就必須實現自然排序介面
*/
public class Student implements Comparable<Student> {
private String name;
private int age;
public Student() {
super();
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Student s) {
// 這裡返回什麼,其實應該根據排序規則來做
// 按照年齡排序,主要條件
int num = this.age - s.age;
// 次要條件
// 年齡相同的時候,還得去看姓名是否也相同
// 如果年齡和姓名都相同,才是同一個元素
int num2 = num == 0 ? this.name.compareTo(s.name) : num;
return num2;
}
}
TreeSetDemo.java
public class TreeSetDemo {
public static void main(String[] args) {
// 建立集合物件
TreeSet<Student> ts = new TreeSet<Student>();
// 建立元素
Student s1 = new Student("linqingxia", 27);
Student s2 = new Student("zhangguorong", 29);
Student s3 = new Student("wanglihong", 23);
Student s4 = new Student("linqingxia", 27);
Student s5 = new Student("liushishi", 22);
Student s6 = new Student("wuqilong", 40);
Student s7 = new Student("fengqingy", 22);
// 新增元素
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
ts.add(s7);
// 遍歷
for (Student s : ts) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}
顯示結果:
3.3 TreeSet的排序規則—比較器排序
集合自身具備比較性。 在集合初始化時,定義一個比較器,將比較器物件作為引數傳遞給TreeSet集合的建構函式。也可以定義一個類,實現Comparator介面,覆蓋compare()方法
我們使用的是直接將比較器物件作為引數傳遞給TreeSet集合的建構函式
public class TreeSetDemo {
public static void main(String[] args) {
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// 姓名長度
int num = s1.getName().length() - s2.getName().length();
// 姓名內容
int num2 = num == 0 ? s1.getName().compareTo(s2.getName())
: num;
// 年齡
int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
return num3;
}
});
// 建立元素
Student s1 = new Student("linqingxia", 27);
Student s2 = new Student("zhangguorong", 29);
Student s3 = new Student("wanglihong", 23);
Student s4 = new Student("linqingxia", 27);
Student s5 = new Student("liushishi", 22);
Student s6 = new Student("wuqilong", 40);
Student s7 = new Student("fengqingy", 22);
Student s8 = new Student("linqingxia", 29);
// 新增元素
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
ts.add(s7);
ts.add(s8);
// 遍歷
for (Student s : ts) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}
結果顯示:符合設定的規定,先比較姓名長度,再比較年齡大小都是按照升序排序
wuqilong---40
fengqingy---22
liushishi---22
linqingxia---27
linqingxia---29
wanglihong---23
zhangguorong---29
第二講 Map
1. Map概述
Map<K,V>介面儲存鍵值對的元素,其中K代表的是鍵,V代表的是值,K是唯一的,不可重複的。
鍵與值的關係:
將鍵對映到值的物件,一個對映不能包含重複的鍵,每個鍵最多隻能對映到同一個值
注意:Map集合的資料結構針對鍵有效,跟值無關
2. Map的功能
1:新增功能
V put(Kkey,V value):新增元素。
如果鍵是第一次儲存,就直接儲存元素,返回null
如果鍵不是第一次存在,就用值把以前的值替換掉,返回以前的值
2:刪除功能
voidclear():移除所有的鍵值對元素
Vremove(Object key):根據鍵刪除鍵值對元素,並把值返回
3:判斷功能
booleancontainsKey(Object key):判斷集合是否包含指定的鍵
booleancontainsValue(Object value):判斷集合是否包含指定的值
booleanisEmpty():判斷集合是否為空
4:獲取功能
Set<Map.Entry<K,V>>entrySet():獲取map所有鍵值對
Vget(Object key):根據鍵獲取值
Set<K> keySet():獲取集合中所有鍵的集合
Collection<V> values():獲取集合中所有值的集合
5:長度功能
intsize():返回集合中的鍵值對的對數
3. 集合的兩種遍歷方式
3.1 通過鍵找值:
思路:A:獲取所有的鍵
B:遍歷鍵的集合,獲取得到每一個鍵
C:根據鍵去找值
public class MapDemo3 {
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
// 建立元素並新增到集合
map.put("楊過", "小龍女");
map.put("郭靖", "黃蓉");
map.put("楊康", "穆念慈");
map.put("陳玄風", "梅超風");
Set<String> set = map.keySet();
for (String s : set) {
String value = map.get(s);
System.out.println(s + "---" + value);
}
}
}
注意:為什麼通過Set儲存鍵集合,因為Set集合具有唯一性的特點,且Set具備迭代器。所以可以通過迭代方式取出鍵,再通過get方法,獲取每一個鍵對應的值。
3.2 鍵值對形式
思路:
A:獲取所有鍵值對物件的集合
B:遍歷鍵值對物件的集合,得到每一個鍵值對物件
C:根據鍵值對物件獲取鍵和值
public class MapDemo4 {
public static void main(String[] args) {
// 建立集合物件
Map<String, String> map = new HashMap<String, String>();
// 建立元素並新增到集合
map.put("楊過", "小龍女");
map.put("郭靖", "黃蓉");
map.put("楊康", "穆念慈");
map.put("陳玄風", "梅超風");
Set<Map.Entry<String, String>> set = map.entrySet();
for (Map.Entry<String, String> me : set) {
String key = me.getKey();
String value = me.getValue();
System.out.println(key + "---" + value);
}
}
}
4. HashMap:
HashMap是基於雜湊表的Map介面實現,雜湊表的作用是保證鍵的唯一性
HashMap<K,V>,如果K為引用型別,需要重寫內部的equals()和hashCode()方法
示例:一個引用型別的遍歷
public class Student {
//省略部分程式碼
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
測試程式碼
public class HashMapDemo4 {
public static void main(String[] args) {
// 建立集合物件
HashMap<Student, String> hm = new HashMap<Student, String>();
// 建立學生物件
Student s1 = new Student("貂蟬", 27);
Student s2 = new Student("王昭君", 30);
Student s3 = new Student("西施", 33);
Student s4 = new Student("楊玉環", 35);
Student s5 = new Student("貂蟬", 27);
// 新增元素
hm.put(s1, "8888");
hm.put(s2, "6666");
hm.put(s3, "5555");
hm.put(s4, "7777");
hm.put(s5, "9999");
Set<Student> set = hm.keySet();
for (Student key : set) {
String value = hm.get(key);
System.out.println(key.getName() + "---" + key.getAge() + "---"
+ value);
}
}
}
測試結果:重複的值根本就沒有儲存在map中
5. TreeMap
TreeMap的鍵是紅黑樹結構,保證鍵的排序性和唯一性
依舊是兩種排序方式:自然排序和比較器排序
示例:比較器排序
public class TreeMapDemo2 {
public static void main(String[] args) {
TreeMap<Student, String> tm = new TreeMap<Student, String>(
new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// 主要條件
int num = s1.getAge() - s2.getAge();
// 次要條件
int num2 = num == 0 ? s1.getName().compareTo(
s2.getName()) : num;
return num2;
}
});
// 建立學生物件
Student s1 = new Student("潘安", 30);
Student s2 = new Student("柳下惠", 35);
Student s3 = new Student("唐伯虎", 33);
Student s4 = new Student("燕青", 32);
Student s5 = new Student("唐伯虎", 33);
// 儲存元素
tm.put(s1, "宋朝");
tm.put(s2, "元朝");
tm.put(s3, "明朝");
tm.put(s4, "清朝");
tm.put(s5, "漢朝");
Set<Student> set = tm.keySet();
for(Student key:set){
String value = tm.get(key);
System.out.println(key.getName() + "---" + key.getAge() + "---"
+ value);
}
}
}
測試結果:可以看出“唐伯虎--33”元素並沒有重複
第三講 Collections
1. Collections類概述
針對集合操作的工具類,都是靜態方法
2. 需要掌握的方法
要知道的方法
public static <T> void sort(List<T> list):排序 預設情況下是自然順序。
public static <T> int binarySearch(List<?> list,T key):二分查詢
public static <T> T max(Collection<?> coll):最大值
public static void reverse(List<?> list):反轉
public static void shuffle(List<?> list):隨機置換,每調一次,元素的位置隨機換一次
示例:Collections類針對自定義物件的排序
/*
* Collections可以針對ArrayList儲存自定義物件的元素排序
*/
public class CollectionsDemo {
public static void main(String[] args) {
// 建立集合物件
List<Student> list = new ArrayList<Student>();
// 建立學生物件
Student s1 = new Student("林青霞", 27);
Student s2 = new Student("風清揚", 30);
Student s3 = new Student("劉曉曲", 28);
Student s4 = new Student("武鑫", 29);
Student s5 = new Student("林青霞", 27);
// 新增元素物件
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
list.add(s5);
// 排序
// 自然排序
// Collections.sort(list);
// 比較器排序
// 如果同時有自然排序和比較器排序,以比較器排序為主
Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s2.getAge() - s1.getAge();
int num2 = num == 0 ? s1.getName().compareTo(s2.getName())
: num;
return num2;
}
});
// 遍歷集合
for (Student s : list) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}