一. Map集合
-
定義
- Map集合是一個(gè)雙列集合,以鍵值對(duì)的形式存在
- 將鍵和值捆綁到一起存放(Map.Entry)
- 一個(gè)映射不能包含重復(fù)的鍵
- 如果出現(xiàn)相同的鍵,會(huì)用新的值覆蓋老的值
- 每個(gè)鍵最多只能映射到一個(gè)值
-
Map接口和Collection接口的不同
- Map是雙列的,Collection是單列的
- Map集合的數(shù)據(jù)結(jié)構(gòu)針對(duì)鍵有效, 跟值無關(guān), Collection 集合的數(shù)據(jù)結(jié)構(gòu)是針對(duì)元素有效
-
常用功能
- 添加方法
- V put(K key , V value): 添加元素
- 如果鍵是第一次存儲(chǔ), 直接存儲(chǔ)元素,返回null
- 如果鍵不是第一個(gè)存在, 就用值把以前的值替換掉,返回以前的值
- V put(K key , V value): 添加元素
- 刪除方法
- void clear() : 移除所有的鍵值對(duì)元素
- V remove(Object key) : 根據(jù)鍵刪除鍵值對(duì)元素, 并把值返回
- 判斷方法
- boolean containsKey(Object key) : 判斷集合是否包含指定的鍵
- boolean containsValue(Object value): 判斷集合是否包含指定的值
- boolean isEmpty: 判斷集合是否為空
- 獲取方法
- Set<Map.Entry<K,V>> entrySet() : 獲取所有的鍵值對(duì)
- V get(Object key) : 根據(jù)鍵獲取值
- Set<K> keySet() : 獲取集合中所有鍵的集合
- Collection<V> values() : 獲取集合中所有值的集合
- int size() : 返回集合中鍵值對(duì)的個(gè)數(shù)
- 添加方法
-
演示
public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); //添加方法 map.put("小紅", 18); map.put("小明", 24); map.put("小輝", 26); map.put("小李", 19); map.put("小王", 18); System.out.println(map); //判斷鍵是否存在 boolean flg = map.containsKey("小紅"); System.out.println(flg); //判斷值是否存在 flg = map.containsValue(18); System.out.println(flg); //判斷集合是否為空 flg = map.isEmpty(); System.out.println(flg); //根據(jù)鍵獲取值 Integer i = map.get("小王"); System.out.println(i); //獲取集合中元素的個(gè)數(shù) int size = map.size(); System.out.println(size); //獲取集合中所有的鍵值對(duì) Set<Map.Entry<String, Integer>> entrySet = map.entrySet(); System.out.println(entrySet); //獲取集合中所有鍵 Set<String> keyset = map.keySet(); System.out.println(keyset); //獲取集合中所有的值 Collection<Integer> valueSet = map.values(); System.out.println(valueSet); }
二. Map集合的遍歷
-
獲取所有鍵的集合的遍歷
- 通過keySet方法獲取到所有鍵的Set集合
- 演示
public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); map.put("小紅", 18); map.put("小明", 24); map.put("小輝", 26); map.put("小李", 19); map.put("小王", 18); Set<String> keyset = map.keySet(); Iterator<String> it = keyset.iterator(); while (it.hasNext()) { String key = it.next(); Integer value = map.get(key); System.out.println("鍵:"+key+" 值:"+value); } }
-
獲取所有的值的遍歷
- 通過values方法獲取所有值的Collection集合
- 演示
public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); map.put("小紅", 18); map.put("小明", 24); map.put("小輝", 26); map.put("小李", 19); map.put("小王", 18); Collection<Integer> values = map.values(); Iterator<Integer> it = values.iterator(); while (it.hasNext()) { Integer value = it.next(); System.out.println("值:"+value); } }
-
獲取所有鍵值對(duì)的遍歷
- 通過entrySet集合獲取所有的鍵值對(duì)的Set集合
- 演示
public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); map.put("小紅", 18); map.put("小明", 24); map.put("小輝", 26); map.put("小李", 19); map.put("小王", 18); Set<Entry<String, Integer>> entrySet = map.entrySet(); Iterator<Entry<String, Integer>> it = entrySet.iterator(); while (it.hasNext()) { Map.Entry<String,Integer> entry = it.next(); String key = entry.getKey(); Integer value = entry.getValue(); System.out.println("鍵:"+key+" 值:"+value); } }
三. HashMap
-
定義
- 底層使用的是數(shù)組
- HashMap就是通過我們存入的key獲取到一個(gè)hash值, 經(jīng)過計(jì)算之后, 獲取到一個(gè)數(shù)組角標(biāo), 然后將key和value封裝到一個(gè)Entry里面, 然后存入數(shù)組
- 當(dāng)數(shù)組容量不夠的時(shí)候, 會(huì)自動(dòng)擴(kuò)容一倍
-
構(gòu)造方法
- HashMap()
- 構(gòu)造一個(gè)具有默認(rèn)初始容量(16) 和默認(rèn)加載因子(0.75)的空HashMap
- HashMap(int initialCapacity)
- 構(gòu)造一個(gè)帶指定初始容量和默認(rèn)加載因子 (0.75) 的空HashMap
- HashMap(int initialCapacity, float loadFactor)
- 構(gòu)造一個(gè)帶指定初始容量和加載因子的空HashMap
- HashMap(Map<? extends K, ?extends V> m)
- 構(gòu)造一個(gè)映射關(guān)系與制定Map相同的新HashMap
- HashMap()
-
常用方法
- put(K key, V value) : 在此映射中關(guān)聯(lián)指定值與指定鍵
- putAll(Map<? extends K, ?extends V> m) : 將另外一個(gè)map集合復(fù)制到此集合中
-
案例
- HashMap集合鍵是Student值是String的案例
- 注意
- 如果我們需要將對(duì)象中的內(nèi)容當(dāng)作比較依據(jù)的話, 就必須要重寫hashCode和equals方法
- 演示
public static void main(String[] args) { Map<Student, String> map = new HashMap<>(); map.put(new Student("小紅", 18), "美女"); map.put(new Student("小李", 18), "老板的小舅子"); for (Entry<Student, String> entry : map.entrySet()) { System.out.println(entry.getKey()+"::"+entry.getValue()); } }
-
測(cè)試題
- 需求: 從鍵盤錄入一串字符, 統(tǒng)計(jì)字符串中每個(gè)字符出現(xiàn)的次數(shù)
- 演示
public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String str = scanner.nextLine(); HashMap<Character, Integer> hm = new HashMap<>();; for (int i = 0; i < str.length(); i++) { char ch = str.charAt(i); if(hm.get(ch)==null) hm.put(ch, 1); else hm.put(ch, hm.get(ch)+1); } System.out.println(hm); scanner.close(); }
四. HashMap和Hashtable的區(qū)別
-
HashMap和Hashtable的區(qū)別
- Hashtable是JDK1.0版本出現(xiàn)的,是線程安全的,效率低,HashMap是JDK1.2版本出現(xiàn)的,是線程不安全的,效率高
- Hashtable不可以存儲(chǔ)null鍵和null值,HashMap可以存儲(chǔ)null鍵和null值
-
案例演示
public static void main(String[] args) { Map<String, String> map = new HashMap<>(); map.put("小紅", "美女"); map.put("小李", "老板的小舅子"); map.put(null, null); Hashtable<String, String> table = new Hashtable<>(); table.put("小紅", "美女"); //table.put(null, null);//會(huì)報(bào)錯(cuò) }
五. TreeMap
-
定義
- TreeMap通過比較元素的大小,對(duì)元素進(jìn)行排序, 最后形成了一個(gè)樹狀結(jié)構(gòu)
- TreeMap中的key需要實(shí)現(xiàn)Comparable接口并重寫compareTo方法, 或者使用Comparator比較器
- 存入元素的時(shí)候,如果會(huì)將新添加的元素的key和集合中已經(jīng)存在的元素的key比較,返回一個(gè)小于0的數(shù),說明,新添加的元素小于已有元素, 如果返回的是一個(gè)等于0的數(shù),說明新添加的元素等于已有元素, value覆蓋, 如果返回一個(gè)大于0的數(shù),說明新添加的元素大于已有元素
-
案例演示
public static void main(String[] args) { Map<String, String> map2 = new TreeMap<>(); map2.put("小紅", "美女"); map2.put("小紅", "老板的小舅子"); System.out.println(map2); }
六. 案例(模擬洗牌和發(fā)牌)
-
演示
public static void main(String[] args) { String[] num = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"}; String[] color = {"方片","梅花","紅桃","黑桃"}; ArrayList<String> poker = new ArrayList<>(); for(String s1 : color) { for(String s2 : num) { poker.add(s1.concat(s2)); } } poker.add("小王"); poker.add("大王"); Random random = new Random(); int count = poker.size(); for (int i = 0; i < count; i++) { int index1 = random.nextInt(count); int index2 = random.nextInt(count); Collections.swap(poker, index1, index2); } List<String> one = new ArrayList<>(); List<String> two = new ArrayList<>(); List<String> three = new ArrayList<>(); List<String> dipai = new ArrayList<>(); /*發(fā)牌*/ for (int i = 0; i < poker.size(); i++) { //最后三張留作底牌 if(i>=poker.size()-3) dipai.add(poker.get(i)); else if(i%3==0) //其他三個(gè)人依次發(fā)牌 one.add(poker.get(i)); else if(i%3==1) two.add(poker.get(i)); else three.add(poker.get(i)); } System.out.println(one); System.out.println(two); System.out.println(three); System.out.println(dipai); }
七. 泛型
-
定義
- 泛型, 即"參數(shù)化類型" , 泛型規(guī)定了類可以使用的應(yīng)用數(shù)據(jù)的類型的范圍
- 泛型,即“參數(shù)化類型”说莫。一提到參數(shù)姑蓝,最熟悉的就是定義方法時(shí)有形參,然后調(diào)用此方法時(shí)傳遞實(shí)參锅移。那么參數(shù)化類型怎么理解呢熔掺?顧名思義,就是將類型由原來的具體的類型參數(shù)化非剃,類似于方法中的變量參數(shù)瞬女,此時(shí)類型也定義成參數(shù)形式(可以稱之為類型形參),然后在使用/調(diào)用時(shí)傳入具體的類型(類型實(shí)參)
- 只在編譯期生效
-
泛型的好處
- 提高安全性(將運(yùn)行期的錯(cuò)誤轉(zhuǎn)換到編譯期)
- 省去強(qiáng)轉(zhuǎn)的麻煩
- 在其作用域內(nèi)可以統(tǒng)一參數(shù)類型
-
泛型的基本使用
- <>中放的必須是引用數(shù)據(jù)類型
- 泛型可以定義來類上和方法上
-
泛型使用注意事項(xiàng)
- 前后的泛型必須一致,或者后面的泛型可以省略不寫(1.7的新特性菱形泛型)
-
泛型的由來
- 類型通過Object 轉(zhuǎn)型問題引入
- 早期的Object類型可以接收任意的對(duì)象類型努潘,但是在實(shí)際的使用中诽偷,會(huì)有類型轉(zhuǎn)換的問題。也就存在這隱患疯坤,所以Java提供了泛型來解決這個(gè)安全問題报慕。
public class Generic { private Object object; public Object getObject() { return object; } public void setObject(Object object) { this.object = object; } }
八. 泛型的使用
-
把泛型定義在類上
-
格式
- public class 類名<泛型類型1,…>
-
注意事項(xiàng)
- 泛型類型必須是引用類型
-
演示
public class Generic<T> { private T t; public Object getObject() { return t; } public void setObject(T t) { this.t = t; } }
-
-
把泛型定義在方法上
-
格式
- public <泛型類型> 返回類型 方法名(泛型類型 變量名)
-
演示
public <E> E method(E[] e){ return e[e.length/2]; }
-
-
把泛型定義在接口上
- 格式
- public interface 接口名<泛型類型>
- 子類去實(shí)現(xiàn)接口的時(shí)候就需要給出具體的類型, 重寫抽象方法的時(shí)候就可以得到具體的類型
- 演示
public interface Inteface<T> { public void method(T t); }
- 格式
-
通配符(了解)
-
泛型通配符<?>
- 任意類型,如果沒有明確压怠,那么就是Object以及任意的Java類了
public static void main(String[] args) { ArrayList<String> arrayList1 = new ArrayList<>(); ArrayList<Integer> arrayList2 = new ArrayList<>(); List<?> list = arrayList1; list = arrayList2; }
-
? extends E
- 向下限定 E 及E的子類
-
? super E
- 向上限定 E及其父類
-
總結(jié)
-
Map集合
- 雙列集合 一次性存兩個(gè)值(key-value)
- key-value : 鍵值對(duì) 映射
- 特性:
- key不能重復(fù), value可以重復(fù)
-
Map集合的方法
map集合的方法都是用來操作key的
put(key)
remove(key) clear
get(key)
-
map集合的遍歷
- map集合沒有自身的遍歷方法, 要先轉(zhuǎn)成set
- keySet():獲取所有的key
- values() : 獲取所有的value
- entrySet() : 獲取所有的鍵值對(duì)
-
HashMap
- 底層是數(shù)組
- 存儲(chǔ)時(shí),通過key算出一個(gè)角標(biāo)值, 如果當(dāng)前位置上有元素, 就比較一下
- 如果對(duì)比成功, 覆蓋值
- 如果沒有成功, 掛載
- 如果當(dāng)前位置上沒有元素, 直接存儲(chǔ)
- hashMap是如何判斷是否重復(fù)的 key的地址值和hashCode和equals方法
-
TreeMap
- 底層是紅黑樹(二叉樹)
- key可以排序
- 新元素要和老元素比較, 根據(jù)返回的結(jié)果判斷存儲(chǔ)的位置
- 參考TreeSet
-
HashSet和TreeSet底層用的HashMap和TreeMap
- 其實(shí)就是將Set集合的元素當(dāng)成Map集合的key
-
泛型
- 設(shè)一個(gè)不是具體類型的類型
- 好處
- 提高代碼的兼容性
- 提高安全性,將運(yùn)行期的錯(cuò)誤提前到編譯期
- 省去強(qiáng)轉(zhuǎn)的麻煩
- 在一定范圍統(tǒng)一類型
- 泛型可以定義的地方
- 接口, 類, 方法
作業(yè)
- 第一題
- 需求:
- 封裝一個(gè)汽車類眠冈,包含String name、int speed屬性,在測(cè)試類中實(shí)例化三個(gè)對(duì)象:c1蜗顽,c2布卡,c3,分別設(shè)置name為:“奧拓”雇盖,“寶馬”忿等,“奔馳”,速度分別設(shè)置為:100,200,300
- 使用Map集合對(duì)象m1將這三個(gè)汽車類對(duì)象保存成key崔挖,然后將int型的汽車價(jià)錢作為值保存在m1的value中贸街,上述三款汽車分別對(duì)應(yīng)的價(jià)錢是10000,500000,2000000
- 解題
- 遍歷m1的鍵,打印name屬性
- 通過合適的方法狸相,求出m1中“寶馬”的價(jià)格薛匪,并打印結(jié)果
- 經(jīng)過降速,所有汽車都降速到原來的80%脓鹃,請(qǐng)打印降速后“寶馬”的速度
- 需求:
- 第二題
- 需求: 創(chuàng)建倆個(gè)List集合,添加一些數(shù)據(jù)逸尖,求它們的并集,差集和交集瘸右。
- 擴(kuò)展題
- 第一題
- 需求: 從鍵盤錄入整數(shù), 打印輸入頻率最高的整數(shù), 如果有多個(gè),就打印多個(gè)
- 第二題
- 需求: 模擬斗地主洗牌發(fā)牌,并對(duì)已發(fā)好的拍進(jìn)行排序(紅桃A,方塊A, 黑桃2.......)
- 第一題