Java數(shù)據(jù)存儲的“雙子星”對決(Map和Set的區(qū)別)
??一、搜索
??1.概念
搜索:是指在數(shù)據(jù)集合過程中查找特定元素或滿足特定條件元素的過程。如:在一組數(shù)組中查找特定的數(shù)字。常見的搜索有直接遍歷和二分查找.....
直接遍歷和二分查找比較適合靜態(tài)類型的查找,即一般不會對區(qū)間進(jìn)行插入和刪除操作。
所以當(dāng)需要動態(tài)查找時,即查找時要進(jìn)行一些插入和刪除,上述的方法并不適用 。如:在學(xué)生系統(tǒng)中,快速查找學(xué)生的成績、統(tǒng)計單詞出現(xiàn)的次數(shù)、確保用戶名唯一(去重)。
Map和Set是一種專門用來進(jìn)行搜索的容器或者數(shù)據(jù)結(jié)構(gòu),是一種適合動態(tài)查找的集合容器。
??2.模型
一般把搜索的數(shù)據(jù)稱為關(guān)鍵字(key),和關(guān)鍵字對應(yīng)的稱為值(value),所以有兩種模型:
- 1.純key模型:由唯一的鍵(key)組成,沒有與鍵直接關(guān)聯(lián)的特定值(value)。
特點:重點在于對鍵的管理和操作,常用于判斷某個元素是否存在。
應(yīng)用場景:數(shù)據(jù)去重,黑名單過濾等......
- 2.key-value模型:是一種鍵(key)和值(value)進(jìn)行相關(guān)聯(lián)的數(shù)據(jù)組織形式。每個鍵都對應(yīng)著一個特定的值,通過鍵可以快速查找、更新與之關(guān)聯(lián)的值。如查找在一串字符串中查找,某個單詞在該字符串中出現(xiàn)的次數(shù)。
特點:鍵是唯一的,用于快速定位和訪問對應(yīng)的值,其值可以是各種類型的數(shù)據(jù)。
應(yīng)用場景:廣泛應(yīng)用于配置文件、數(shù)據(jù)庫等,比如,以用戶ID為鍵,存儲用戶姓名等為值。
Set只存儲了key,Map存儲的就是key—value的鍵對值。
??二、Map
??1.什么是Map?
Map是接口類,該類沒有繼承Collection,儲存的是<K,V>結(jié)構(gòu)的鍵值對,并且K一定是唯一的,不能重復(fù)。
??2.Map的實例化
Map<K,V>是將鍵(key)與值(value)進(jìn)行關(guān)聯(lián)的數(shù)據(jù)結(jié)構(gòu),K代表鍵的類型,V代表值的類型。
Map的實現(xiàn)類主要有HashMap,TreeMap
實例化的實現(xiàn):
public static void main(String[] args) { Map<String,Integer> map1=new HashMap<>(); Map<String,Integer> map2=new TreeMap<>(); }
Map是一個接口,不能直接實例化對象,如果要實例化對象只能通過其實現(xiàn)類TreeMap或者HashMap來實現(xiàn)
??3.Map的常見方法
方法 | 解釋 |
V put(K key,V value) | 設(shè)置key值與value值相關(guān)聯(lián) |
V remove(Object key) | 將key對應(yīng)的映射關(guān)系刪除 |
V remove(Object key,Object value) | 只有指定的鍵與指定的值相匹配時才可以刪除 |
V get(Object key) | 返回key對應(yīng)的value值 |
V getOrDefault(Object key,V defalutValue) | 返回key對應(yīng)的value,key不存在,返回默認(rèn)值 |
Set<K> keySet() | 返回key中的不重復(fù)集合 |
Collection<V> values() | 返回value的可重復(fù)集合 |
Set<Map.Entry<K,V>> entrySet() | 返回所有的key-value的映射關(guān)系 |
boolean containsKey(Object key) | 判斷是否包含key |
boolean containsValue(Object value) | 判斷是否包含value |
??4.Map方法的使用
public static void main(String[] args) { Map<String,Integer> map=new HashMap<>(); //map:設(shè)置k,v值 map.put("a",2); map.put("c",5); map.put("s",21); //get:獲取key對應(yīng)的value值 System.out.println(map.get("a"));//2 System.out.println(map.get("b"));//不存在key值,其默認(rèn)值為null //getOrDefault: //如果map中有key值,返回key對應(yīng)的value1值,否則返回設(shè)置的默認(rèn)值 System.out.println(map.getOrDefault("a",1));//2 System.out.println(map.getOrDefault("b",3));//3 //remove1:如果key值與指定的值相匹配,刪除;否則,不刪除 map.remove("a",1);//不匹配不刪除 System.out.println(map.get("a"));//a對應(yīng)的value還是2 //remove2:刪除key對應(yīng)的value值 map.remove("a"); System.out.println(map.get("a"));//null //containsKey:判斷是否包含key System.out.println(map.containsKey("c"));//true //containsValue:判斷是否包含value值 System.out.println(map.containsValue(10));//false Map<String,Integer> map1=new TreeMap<>(); map1.put("a",2); map1.put("a",3); map1.put("b",3); map1.put("c",6); //Set<K> keySet:返回key中不重復(fù)的集合 Set<String> keySet=map1.keySet(); System.out.println(keySet);//[a, b, c] //Collection<V> values:返回value中可重復(fù)的集合 Collection<Integer> value=map1.values(); System.out.println(value);//[3, 3, 6] //Set<K,V>> entrySet:返回key-value所有的映射關(guān)系 Set<Map.Entry<String,Integer>> entrySet=map1.entrySet(); System.out.println(entrySet);//[a=3, b=3, c=6] }
注意事項:
Map中存放鍵值對的Key是唯一的,value是可重復(fù)的,當(dāng)put相同的key,不同的value值時,只是將key所對應(yīng)的value值進(jìn)行替換,以最后存放的value為主;
public static void main(String[] args) { Map<String,Integer> map=new HashMap<>(); map.put("a",11); map.put("a",24); map.put("a",15); System.out.println(map.get("a"));//15 }
在HashMap中存放的key和value可以都為空,在TreeMap中插入鍵對值時,key不能為空,value可以為空;
HashMap
public static void main(String[] args) { Map<String,Integer> map1=new HashMap<>(); map1.put("a",null); map1.get("a");//無異常 map1.put(null,null); map1.get(null);//無異常 }
TreeMap
public static void main(String[] args) { Map<String,Integer> map1=new TreeMap<>(); map1.put("a",null); map1.get("a");//無異常 map1.put(null,2); map1.get(null);//報錯 }
- Map中鍵值對的key不能直接修改,可以直接修改value值,如果要修改key,只能將key刪除,在進(jìn)行重新插入。
- HashMap和TreeMap是Map的接口實現(xiàn)類,用于存儲鍵對值數(shù)據(jù),以下是他們的區(qū)別:
Map的底層結(jié)構(gòu) | TreeMap | HashMap |
底層結(jié)構(gòu) | 紅黑樹 | 哈希表(數(shù)組+鏈表/紅黑樹) |
插入/刪除/查找時間復(fù)雜度 | O(log2N) | O(1) |
是否有序 | 關(guān)于Key有序 | 無序 |
允許null鍵 | 不允許,需可比較 | 允許null鍵 |
線程安全 | 不安全 | 不安全 |
插入/刪除/查找區(qū)別 | 需要進(jìn)行元素比較 | 通過哈希函數(shù)計算哈希地址 |
比較與覆寫 | key必須能夠比較,否則會拋出異常 | 自定義類型需要覆寫equals和hashCode方法 |
應(yīng)用場景 | 需要key有序 | 無序有序,需要更高的時間性能 |
??三、Set
??1.什么是Set?
Set是一個接口,繼承自Collection接口,有HashSet、TreeSet等實現(xiàn)類,HashSet基于哈希表實現(xiàn),不保證元素有序;TreeSet基于紅黑樹實現(xiàn),會對元素進(jìn)行排序。
??2.Set的常見方法
方法 | 解釋 |
boolean add(E e) | 添加元素,但元素重復(fù)不添加 |
boolean remove(Object o) | 刪除集合中元素o |
boolean contains(Object o) | 判斷o是否包含在集合中 |
boolean isEmpty() | 檢測是否為空,為空返回false,否則返回true |
void clear() | 清空 |
Iterator<E> iterator() | 使用迭代器遍歷集合中的對象 |
int size() | 返回set中元素個數(shù) |
Object[] toArray() | 將set中的元素轉(zhuǎn)換為數(shù)組返回 |
boolean containsAll(Collection<?>c) | 集合中的元素是否在set中的全部存在,是返回true,否則返回false |
boolean addAll(Collection<? extend) | 將集合c中的元素添加到set中,可以達(dá)到去重的效果 |
??3.Set方法的使用
public static void main(String[] args) { public static void main(String[] args) { Set<Integer> set1=new HashSet<>(); //add:添加元素 set1.add(5); set1.add(20); set1.add(15); set1.add(8); //remove:移除元素 set1.remove(20); //是否包含該元素 System.out.println(set1.contains(5));//true System.out.println(set1.contains(2));//false //Iterator:遍歷集合 Iterator<Integer> iterator=set1.iterator(); while(iterator.hasNext()){ System.out.print(iterator.next()+" ");//5 8 15 } System.out.println(); //isEmpty:判斷是否為空 System.out.println(set1.isEmpty());//false:不為空 //size:計算元素個數(shù) System.out.println(set1.size());//3 //toArray:將set中的元素轉(zhuǎn)換為數(shù)組 Integer[] toArray=set1.toArray(new Integer[0]); for (Integer x:toArray) { System.out.print(x+" ");//5 8 15 } System.out.println(); //containsAll:set是否包含指定集合的所有元素 Set<Integer> set2=new HashSet<>(); set2.add(1); set2.add(2); set2.add(3); Set<Integer> set3=new HashSet<>(); set3.add(1); set3.add(2); //看set2中是否都包含set3集合中的元素 boolean containsAll=set2.containsAll(set3); System.out.println(containsAll);//true //addAll:將集合中的元素添加到set中 Set<Integer> set4=new TreeSet<>(); set4.add(1); set4.add(5); set4.add(19); Set<Integer> set5=new TreeSet<>(); set5.add(2); set5.add(1); set5.add(6); boolean addAll=set4.addAll(set5); Iterator<Integer> iterator1=set4.iterator(); while(iterator1.hasNext()){ //如果是HashSet那么不自動排序,如果是TreeSet就自動排序 System.out.print(iterator1.next()+" ");//1 2 5 6 19 }
注意:
- Set只存儲了key,并且要求key一定要唯一,其key值不能進(jìn)行修改,如果要進(jìn)行修改需要刪除后再插入。
- Set可以對集合進(jìn)行去重;
- TreeSet的底層是使用Map來實現(xiàn)的,其使用key與Object的一個默認(rèn)對象作為鍵值對插入到Map中;
- TreeSet和HashSet的區(qū)別
Set底層結(jié)構(gòu) | TreeSet | HashSet |
底層結(jié)構(gòu) | 紅黑樹 | 哈希表 |
插入/刪除/查找時間復(fù)雜度 | O(log2N) | O(1) |
是否有序 | key有序 | 不一定有序 |
允許null鍵 | 不允許,需可比較 | 允許null鍵 |
線程安全 | 不安全 | 不安全 |
插入/刪除/查找區(qū)別 | 按照紅黑樹的特性來進(jìn)行插入和刪除 | 1.先計算key哈希地址2.然后進(jìn)行插入和刪除 |
比較與覆寫 | key必須能夠比較,否則會拋出ClassCastException異常 | 自定義類型需要覆寫equals和hashCode方法 |
應(yīng)用場景 | 需要key有序 | 無關(guān)有序,需要更高的時間性能 |
??四、Map和Set的區(qū)別
區(qū)別 | Map | Set |
存儲形式 | 是一種鍵對值(key-value)集合 | 是值的集合,值存在單一的值,不存在重復(fù)元素 |
訪問方式 | get(key)方法 | 沒有鍵對值的映射,一般通過for循環(huán)或者迭代器遍歷 |
唯一性 | 鍵是唯一的,不用重復(fù),值可以重復(fù) | 所有元素都是唯一的 |
應(yīng)用場景 | 需要建立映射關(guān)系的場景 | 需要確保元素唯一的場景 |
到此這篇關(guān)于Java數(shù)據(jù)存儲的“雙子星”對決的文章就介紹到這了,更多相關(guān)Java數(shù)據(jù)存儲內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java GUI圖形界面開發(fā)實現(xiàn)小型計算器流程詳解
本文章向大家介紹Java GUI圖形界面開發(fā)實現(xiàn)小型計算器,主要包括布局管理器使用實例、應(yīng)用技巧、基本知識點總結(jié)和需要注意事項,具有一定的參考價值,需要的朋友可以參考一下2022-08-08SpringBoot的@EnableAsync和@Async注解分析
這篇文章主要介紹了SpringBoot的@EnableAsync和@Async注解分析,Spring Boot是一個快速開發(fā)框架,可以幫助開發(fā)人員快速構(gòu)建基于Spring的應(yīng)用程序,需要的朋友可以參考下2023-07-07Java中String類getBytes()方法詳解與完整實例
這篇文章主要給大家介紹了關(guān)于Java中String類getBytes()方法詳解與完整實例的相關(guān)資料,getBytes()是Java編程語言中將一個字符串轉(zhuǎn)化為一個字節(jié)數(shù)組byte[]的方法,需要的朋友可以參考下2023-10-10Mybatis Plus select 實現(xiàn)只查詢部分字段
這篇文章主要介紹了Mybatis Plus select 實現(xiàn)只查詢部分字段的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09Spring實現(xiàn)HikariCP連接池的示例代碼
在SpringBoot 2.0中,我們使用默認(rèn)連接池是HikariCP,本文講一下HikariCP的具體使用,具有一定的參考價值,感興趣的可以了解一下2021-08-08ObjectInputStream 和 ObjectOutputStream 介紹_動力節(jié)點Java學(xué)院整理
ObjectInputStream 和 ObjectOutputStream 的作用是,對基本數(shù)據(jù)和對象進(jìn)行序列化操作支持。本文給大家詳細(xì)介紹了ObjectInputStream 和 ObjectOutputStream的相關(guān)知識,感興趣的朋友一起學(xué)習(xí)吧2017-05-05