三攒盈、Collections
java.utils.Collections 是集合工具類劈伴,用來對(duì)集合進(jìn)行操作。部分方法如下:
- public static <T> boolean addAll(Collection<T> c, T... elements) :往集合中添加一些元素。
- public static void shuffle(List<?> list) 打亂順序 :打亂集合順序陨闹。
- public static <T> void sort(List<T> list) :將集合中元素按照默認(rèn)規(guī)則排序。
- public static <T> void sort(List<T> list薄坏,Comparator<? super T> ) :將集合中元素按照指定規(guī)則排序正林。
public class CollectionsDemo {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
//原來寫法
//list.add(12);
//list.add(14);
//list.add(15);
//list.add(1000);
//采用工具類 完成 往集合中添加元素
Collections.addAll(list, 5, 222, 1,2);
System.out.println(list);
//排序方法
Collections.sort(list);
System.out.println(list);
}
}
結(jié)果:
[5, 222, 1, 2]
[1, 2, 5, 222]
代碼演示之后 颤殴,發(fā)現(xiàn)我們的集合按照順序進(jìn)行了排列觅廓,可是這樣的順序是采用默認(rèn)的順序,如果想要指定順序那該 怎么辦呢涵但?
Comparator比較器
1.public static <T> void sort(List<T> list) :將集合中元素按照默認(rèn)規(guī)則排序杈绸。 不過這次存儲(chǔ)的是字符串類型。
public class CollectionsDemo2 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("cba");
list.add("aba");
list.add("sba");
list.add("nba");
//排序方法
Collections.sort(list);
System.out.println(list);
}
}
結(jié)果:[aba, cba, nba, sba]
我們使用的是默認(rèn)的規(guī)則完成字符串的排序矮瘟,那么默認(rèn)規(guī)則是怎么定義出來的呢瞳脓? 說到排序了,簡(jiǎn)單的說就是兩個(gè)對(duì)象之間比較大小澈侠,那么在JAVA中提供了兩種比較實(shí)現(xiàn)的方式劫侧,一種是比較死板的采用 java.lang.Comparable 接口去實(shí)現(xiàn),一種是靈活的當(dāng)我需要做排序的時(shí)候在去選擇的 java.util.Comparator 接口完成。
那么我們采用的 public static <T> void sort(List<T> list) 這個(gè)方法完成的排序烧栋,實(shí)際上要求了被排序的類型 需要實(shí)現(xiàn)Comparable接口完成比較的功能写妥,在String類型上如下:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {}
String類實(shí)現(xiàn)了這個(gè)接口,并完成了比較規(guī)則的定義审姓,但是這樣就把這種規(guī)則寫死了珍特,那比如我想要字符串按照第 一個(gè)字符降序排列,那么這樣就要修改String的源代碼魔吐,這是不可能的了扎筒,那么這個(gè)時(shí)候我們可以使用
public static <T> void sort(List<T> list,Comparator<? super T> )
方法靈活的完成酬姆,這個(gè)里面就涉及到了 Comparator這個(gè)接口嗜桌,位于位于java.util包下,排序是comparator能實(shí)現(xiàn)的功能之一,該接口代表一個(gè)比較器辞色,比 較器具有可比性症脂!顧名思義就是做排序的,通俗地講需要比較兩個(gè)對(duì)象誰排在前誰排在后淫僻,那么比較的方法就是:
public int compare(String o1, String o2) :比較其兩個(gè)參數(shù)的順序诱篷。
小提示:
兩個(gè)對(duì)象比較的結(jié)果有三種:大于,等于雳灵,小于棕所。
- 如果要按照升序排序, 則o1 小于o2悯辙,返回(負(fù)數(shù))琳省,相等返回0,01大于02返回(正數(shù))
- 如果要按照 降序排序 則o1 小于o2躲撰,返回(正數(shù))针贬,相等返回0,01大于02返回(負(fù)數(shù))
public class CollectionsDemo3 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("cba");
list.add("aba");
list.add("sba");
list.add("nba");
//排序方法 按照第一個(gè)單詞的降序
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.charAt(0) ‐ o1.charAt(0);
}
});
System.out.println(list);
}
}
匿名內(nèi)部類
匿名內(nèi)部類 :是內(nèi)部類的簡(jiǎn)化寫法拢蛋。它的本質(zhì)是一個(gè) 帶具體實(shí)現(xiàn)的 父類或者父接口的 匿名的 子類對(duì)象桦他。 開發(fā)中,最常用到的內(nèi)部類就是匿名內(nèi)部類了谆棱。以接口舉例快压,當(dāng)你使用一個(gè)接口時(shí),似乎得做如下幾步操作垃瞧,
- 定義子類
- 重寫接口中的方法
- 創(chuàng)建子類對(duì)象
- 調(diào)用重寫后的方法 我們的目的蔫劣,最終只是為了調(diào)用方法,那么能不能簡(jiǎn)化一下个从,把以上四步合成一步呢脉幢?
匿名內(nèi)部類就是做這樣的快 捷方式
前提:
匿名內(nèi)部類必須繼承一個(gè)父類或者實(shí)現(xiàn)一個(gè)父接口歪沃。
格式:
new 父類名或者接口名(){
// 方法重寫
@Override
public void method() {
// 執(zhí)行語句
}
};
以接口為例,匿名內(nèi)部類的使用嫌松,代碼如下:
public abstract class FlyAble{
public abstract void fly();
}
創(chuàng)建匿名內(nèi)部類沪曙,并調(diào)用:
public class InnerDemo {
public static void main(String[] args) {
/*1.等號(hào)右邊:是匿名內(nèi)部類,定義并創(chuàng)建該接口的子類對(duì)象 2.等號(hào)左邊:是多態(tài)賦值,接口類型引用指向子類對(duì)象 */
FlyAble f = new FlyAble(){
public void fly() {
System.out.println("我飛了~~~");
}
};
//調(diào)用 fly方法,執(zhí)行重寫后的方法
f.fly();
}
}
public class InnerDemo2 {
public static void main(String[] args) {
/*1.等號(hào)右邊:定義并創(chuàng)建該接口的子類對(duì)象 2.等號(hào)左邊:是多態(tài),接口類型引用指向子類對(duì)象 */
FlyAble f = new FlyAble(){
public void fly() {
System.out.println("我飛了~~~");
}
};
// 將f傳遞給showFly方法中
showFly(f);
}
public static void showFly(FlyAble f) {
f.fly();
}
}
以上兩步豆瘫,也可以簡(jiǎn)化為一步,代碼如下:
public class InnerDemo3 {
public static void main(String[] args) {
/*創(chuàng)建匿名內(nèi)部類,直接傳遞給showFly(FlyAble f) */
showFly( new FlyAble(){
public void fly() {
System.out.println("我飛了~~~");
}
});
}
public static void showFly(FlyAble f) {
f.fly();
}
}
四菊值、 Map集合
現(xiàn)實(shí)生活中外驱,我們常會(huì)看到這樣的一種集合:IP地址與主機(jī)名,身份證號(hào)與個(gè)人腻窒,系統(tǒng)用戶名與系統(tǒng)用戶對(duì)象等昵宇, 這種一一對(duì)應(yīng)的關(guān)系,就叫做映射儿子。Java提供了專門的集合類用來存放這種對(duì)象關(guān)系的對(duì)象瓦哎,即 java.util.Map 接 口。我們通過查看 Map 接口描述柔逼,發(fā)現(xiàn) Map 接口下的集合與 Collection 接口下的集合蒋譬,它們存儲(chǔ)數(shù)據(jù)的形式不同,如下圖愉适。
- Collection 中的集合犯助,元素是孤立存在的(理解為單身),向集合中存儲(chǔ)元素采用一個(gè)個(gè)元素的方式存儲(chǔ)维咸。
- Map 中的集合剂买,元素是成對(duì)存在的(理解為夫妻)。每個(gè)元素由鍵與值兩部分組成癌蓖,通過鍵可以找對(duì)所對(duì)應(yīng)的 值瞬哼。
- Collection 中的集合稱為單列集合,
- Map 中的集合稱為雙列集合租副。
需要注意的是坐慰, Map 中的集合不能包含重復(fù)的鍵,值可以重復(fù)用僧;每個(gè)鍵只能對(duì)應(yīng)一個(gè)值讨越。
Map常用子類
通過查看Map接口描述,看到Map有多個(gè)子類永毅,這里我們主要講解常用的HashMap集合把跨、LinkedHashMap集合。
1.HashMap:存儲(chǔ)數(shù)據(jù)采用的哈希表結(jié)構(gòu)沼死,元素的存取順序不能保證一致着逐。由于要保證鍵的唯一、不重復(fù),需 要重寫鍵的hashCode()方法耸别、equals()方法健芭。
2.LinkedHashMap:HashMap下有個(gè)子類LinkedHashMap,存儲(chǔ)數(shù)據(jù)采用的哈希表結(jié)構(gòu)+鏈表結(jié)構(gòu)秀姐。通過鏈 表結(jié)構(gòu)可以保證元素的存取順序一致慈迈;通過哈希表結(jié)構(gòu)可以保證的鍵的唯一、不重復(fù)省有,需要重寫鍵的 hashCode()方法痒留、equals()方法。
方法:
- public V put(K key, V value) : 把指定的鍵與指定的值添加到Map集合中蠢沿。
- public V remove(Object key) : 把指定的鍵 所對(duì)應(yīng)的鍵值對(duì)元素 在Map集合中刪除伸头,返回被刪除元素的 值。
- public V get(Object key) 根據(jù)指定的鍵舷蟀,在Map集合中獲取對(duì)應(yīng)的值恤磷。
- public Set<K> keySet() : 獲取Map集合中所有的鍵,存儲(chǔ)到Set集合中野宜。
- public Set<Map.Entry<K,V>> entrySet() : 獲取到Map集合中所有的鍵值對(duì)對(duì)象的集合(Set集合)扫步。
public class MapDemo {
public static void main(String[] args) {
//創(chuàng)建 map對(duì)象
HashMap<String, String> map = new HashMap<String, String>();
//添加元素到集合
map.put("黃曉明", "楊穎");
map.put("文章", "馬伊琍");
map.put("鄧超", "孫儷");
System.out.println(map);
//String remove(String key)
System.out.println(map.remove("鄧超"));
System.out.println(map);
// 想要查看 黃曉明的媳婦 是誰
System.out.println(map.get("黃曉明"));
System.out.println(map.get("鄧超"));
}
}
提示:
- 使用put方法時(shí),若指定的鍵(key)在集合中沒有匈子,則沒有這個(gè)鍵對(duì)應(yīng)的值锌妻,返回null,并把指定的鍵值添加到 集合中旬牲;
- 若指定的鍵(key)在集合中存在仿粹,則返回值為集合中鍵對(duì)應(yīng)的值(該值為替換前的值),并把指定鍵所對(duì)應(yīng)的 值原茅,替換成指定的新值吭历。
Map集合遍歷鍵找值方式
鍵找值方式:即通過元素中的鍵,獲取鍵所對(duì)應(yīng)的值
- 獲取Map中所有的鍵擂橘,由于鍵是唯一的晌区,所以返回一個(gè)Set集合存儲(chǔ)所有的鍵。方法提示: keyset()
- 遍歷鍵的Set集合通贞,得到每一個(gè)鍵朗若。
- 根據(jù)鍵,獲取鍵所對(duì)應(yīng)的值昌罩。方法提示: get(K key)
public class MapDemo01 {
public static void main(String[] args) {
//創(chuàng)建Map集合對(duì)象
HashMap<String, String> map = new HashMap<String,String>();
//添加元素到集合
map.put("胡歌", "霍建華");
map.put("郭德綱", "于謙");
map.put("薛之謙", "大張偉");
//獲取所有的鍵 獲取鍵集
Set<String> keys = map.keySet();
// 遍歷鍵集 得到 每一個(gè)鍵
for (String key : keys) {
//key 就是鍵 //獲取對(duì)應(yīng)值
String value = map.get(key);
System.out.println(key+"的CP是:"+value);
}
}
}
Entry鍵值對(duì)對(duì)象
我們已經(jīng)知道哭懈, Map 中存放的是兩種對(duì)象,一種稱為key(鍵)茎用,一種稱為value(值)遣总,它們?cè)谠?Map 中是一一對(duì)應(yīng)關(guān) 系睬罗,這一對(duì)對(duì)象又稱做 Map 中的一個(gè) Entry(項(xiàng)) 。 Entry 將鍵值對(duì)的對(duì)應(yīng)關(guān)系封裝成了對(duì)象旭斥。即鍵值對(duì)對(duì)象容达,這 樣我們?cè)诒闅v Map 集合時(shí),就可以從每一個(gè)鍵值對(duì)( Entry )對(duì)象中獲取對(duì)應(yīng)的鍵與對(duì)應(yīng)的值垂券。
既然Entry表示了一對(duì)鍵和值花盐,那么也同樣提供了獲取對(duì)應(yīng)鍵和對(duì)應(yīng)值得方法:
- public K getKey() :獲取Entry對(duì)象中的鍵。
- public V getValue() :獲取Entry對(duì)象中的值菇爪。
在Map集合中也提供了獲取所有Entry對(duì)象的方法: - public Set<Map.Entry<K,V>> entrySet() : 獲取到Map集合中所有的鍵值對(duì)對(duì)象的集合(Set集合)算芯。
public class MapDemo02 {
public static void main(String[] args) {
// 創(chuàng)建Map集合對(duì)象
HashMap<String, String> map = new HashMap<String,String>();
// 添加元素到集合
map.put("胡歌", "霍建華");
map.put("郭德綱", "于謙");
map.put("薛之謙", "大張偉");
// 獲取 所有的 entry對(duì)象
entrySet Set<Entry<String,String>> entrySet = map.entrySet();
// 遍歷得到每一個(gè)entry對(duì)象
for (Entry<String, String> entry : entrySet) {
// 解析
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"的CP是:"+value);
}
}
}
HashMap存儲(chǔ)自定義類型鍵值
練習(xí):每位學(xué)生(姓名,年齡)都有自己的家庭住址娄帖。那么也祠,既然有對(duì)應(yīng)關(guān)系昙楚,則將學(xué)生對(duì)象和家庭住址存儲(chǔ)到 map集合中近速。學(xué)生作為鍵, 家庭住址作為值。
public class Student {
private String name;
private int age; public Student() {
}
public Student(String name, int age) {
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 boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass())
return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
編寫測(cè)試類:
public class HashMapTest {
public static void main(String[] args) {
//1,創(chuàng)建Hashmap集合對(duì)象堪旧。
Map<Student,String> map = new HashMap<Student,String>();
//2,添加元素削葱。
map.put(new Student("lisi",28), "上海");
map.put(new Student("wangwu",22), "北京");
map.put(new Student("zhaoliu",24), "成都");
map.put(new Student("zhouqi",25), "廣州");
map.put(new Student("wangwu",22), "南京");
//3,取出元素。鍵找值方式
Set<Student> keySet = map.keySet();
for(Student key: keySet){
String value = map.get(key);
System.out.println(key.toString()+"....."+value);
}
}
}
當(dāng)給HashMap中存放自定義對(duì)象時(shí)淳梦,如果自定義對(duì)象作為key存在析砸,這時(shí)要保證對(duì)象唯一,必須復(fù)寫對(duì)象的 hashCode和equals方法爆袍。 如果要保證map中存放的key和取出的順序一致首繁,可以使用 java.util.LinkedHashMap 集合來存放。
LinkedHashMap
我們知道HashMap保證成對(duì)元素唯一陨囊,并且查詢速度很快弦疮,可是成對(duì)元素存放進(jìn)去是沒有順序的,那么我們要保 證有序蜘醋,還要速度快怎么辦呢胁塞? 在HashMap下面有一個(gè)子類LinkedHashMap,它是鏈表和哈希表組合的一個(gè)數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)压语。
public class LinkedHashMapDemo {
public static void main(String[] args) {
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
map.put("鄧超", "孫儷");
map.put("李晨", "范冰冰");
map.put("劉德華", "朱麗倩");
Set<Entry<String, String>> entrySet = map.entrySet();
for (Entry<String, String> entry : entrySet) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
}