java中的常用集合類整理
集合、數(shù)組都是對多個數(shù)據(jù)進(jìn)行存儲操作(主要是內(nèi)存層面存儲)的結(jié)構(gòu),簡稱Java容器。
數(shù)組的特點(diǎn)
1.數(shù)組初始化以后,長度確定不可變
2.數(shù)組定義好,其元素的類型確定不可變(可能有多態(tài)性)
3.數(shù)組中提供的方法有限,對于添加、刪除、插入數(shù)據(jù)等操作不方便。
4.獲取數(shù)組中實(shí)際元素的個數(shù)是沒有辦法的。
5.數(shù)組存儲數(shù)據(jù)的特點(diǎn)是有序、可重復(fù)的。
Java集合可分為Collection和Map兩種體系,集合存儲的優(yōu)點(diǎn)是解決數(shù)組存儲數(shù)據(jù)方面的弊端。
- Collection接口:單列數(shù)據(jù),用來存儲一個一個的對象
- List接口:元素有序,可重復(fù)的集合 --> '動態(tài)'數(shù)組
- Set接口 :元素?zé)o序、不可重復(fù)的集合
- Map接口:雙列數(shù)據(jù),保存有映射關(guān)系(鍵值對)的集合
Collection接口
向collection接口的實(shí)現(xiàn)類的對象中添加數(shù)據(jù)obj時,要求obj所在類要重寫equals方法。
Abstract Methods
add(Object e):
將元素e添加到集合中
size():
獲取添加的元素個數(shù)
addAll(Collection coll):
將形參coll集合的元素添加到當(dāng)前集合中
clear():
清空集合元素,集合仍然存在,只是集合里沒有元素
isEmpty():
判斷當(dāng)前集合是否為空
contains(Object obj):
判斷當(dāng)前集合中是否包含obj,是否包含是通過調(diào)用obj的equals判斷
containsAll(Collection coll):
判斷形參coll中的所有元素是否都存在當(dāng)前集合中。
remove(Object obj):
移除某個元素,同樣通過equals尋找移除的元素
removeAll(Collection coll):
從當(dāng)前集合中移除coll集合中所有的元素,需要調(diào)用equals函數(shù)
retainAll(Collection coll):
求兩個集合的交集,結(jié)果為修改當(dāng)前集合后的集合。
equals(Collection coll):
比較兩個集合是否一樣。
hashCode():
返回當(dāng)前對象的哈希值
集合的遍歷:iterator 接口
集合元素的遍歷操作:Iterator迭代器接口。只能遍歷集合Collection,map不行
Iterator <E> iterator = coll.iterator(); //方式一:通過iterator.next()獲得集合元素 iterator.next(); //方式二:循環(huán),不推薦 for(int i =0;i<coll.size;i++){ iterator.next(); } //方式三:推薦! //hasNext():判斷是否還有下一個元素 while(iterator.hasNext()){ //next():①指針下移 ②將下移以后集合位置上的元素返回 Object obj = iterator.next(); if("Tom".equals(obj)){ //iterator中的remove(),刪除集合中的元素 iterator.remove() } } //方法引用,Java8新特性 coll.forEach(System.out::println)
集合的遍歷:增強(qiáng)for循環(huán)
增強(qiáng)for循環(huán)用于遍歷數(shù)組和集合(colleciton)
格式:集合元素的類型 局部變量:集合
//第一個位置,是當(dāng)前的元素 //第二個位置,是遍歷的對象 //集合元素的類型 局部變量 :集合 for(Object obj : coll){}
面試題
知識點(diǎn):增強(qiáng)for只能遍歷不能賦值
集合元素的類型 局部變量:集合
相當(dāng)于從集合中取出賦值給局部變量,集合本身是沒有修改的。
String [] arr = new String[]{"ranan","ranan"} //普通for循環(huán) for(int i=0;i<arr.length;i++){ arr[i] = "xx" } for(int i=0;i<arr.length;i++){ System.out.println(arr[i]); //輸出"xx" } //增強(qiáng)for循環(huán) for(String s:arr){ //這里的s是局部變量,相當(dāng)與取出arr[i]的值賦值給了變量s,改變的是s的值 s = "xx"; } for(int i=0;i<arr.length;i++){ System.out.println(arr[i]); //輸出"ranan" }
List接口
比較ArrayList、LinkedList、Vector的異同
同:三各類都實(shí)現(xiàn)了List接口,存儲數(shù)據(jù)的特點(diǎn)相同:存儲有序的、可重復(fù)異:
- ArrayList:List接口的主要實(shí)現(xiàn)類,線程不安全、效率高,底層使用Object[]存儲,默認(rèn)擴(kuò)容為原數(shù)組的1.5倍
- LinkedList:底層使用雙向鏈表存儲,對于頻繁的插入、刪除操作效率更高
- Vector:List接口的古老實(shí)現(xiàn)類,線程安全、效率低,底層使用Object[]存儲,默認(rèn)長度為10。默認(rèn)擴(kuò)容為原數(shù)組的2倍
ArrayList
JDK7
//底層創(chuàng)建了長度是10的object[]數(shù)組 ArrayList <Integer> list = new ArrayList<Integer>();//一般擴(kuò)容原來的一半,將原數(shù)組元素復(fù)制到新數(shù)組 List add(123) //底層使用Object[]數(shù)組存儲,elementData[0]= new Integer(123) ArrayList list = new ArrayList(數(shù)字)
結(jié)論:建議開發(fā)中使用帶參的構(gòu)造器
JDK8
ArrayList list = new ArrayList() //底層的object[] elementData初始化為{},并沒有創(chuàng)建長度為10的數(shù)組
懶漢式,底層的object[] elementData初始化為{},并沒有創(chuàng)建長度為10的數(shù)組,第一次調(diào)用add方法時才new創(chuàng)建好數(shù)組。后續(xù)的添加和擴(kuò)容操作與jdk7中一樣。
區(qū)別:JDK7中的ArrayList對象的創(chuàng)建類似于單例的餓漢式,而JDK8中的類似于單例的懶漢式,延遲了數(shù)組的創(chuàng)建,節(jié)省內(nèi)存
LinkedList
LinkedList = new LinkedList()//內(nèi)部聲明了Node類型的first與last,值為null
removeLast():移除最后一個元素
List的常用方法
List集合添加了一些根據(jù)索引來操作集合元素的方法,因為List是有序的
void add(int index,Object ele):
在index位置插入ele元素
boolean addAll(int index,Collection eles):
從index位置開始依次插入eles中的所有元素
Object get(int index):
獲取指定index位置的元素
int indexOf(Object obj):
返回obj在集合中首次出現(xiàn)的位置
int LastIndexOf(Object obj):
返回obj在集合中最后一次出現(xiàn)的位置
Object remove(int index):
移除指定index位置的元素,并返回此元素
Object set(int index,Object ele):
設(shè)置指定index位置的元素為ele
List subList(int fromIndex,int toIndex):
返回從fromIndex到toIndex位置的子集合
常用方法
增:add(Object obj)
刪:remove(int index)/remove(Obejct obj)
改:set(int index,Object ele)
查:get(int index)
插:add(int index,Object ele)
長度:size()
遍歷:Iterator
迭代器方法/增強(qiáng)for循環(huán)/普通的循環(huán)
集合與數(shù)組的轉(zhuǎn)換
集合轉(zhuǎn)換成數(shù)組 --> coll.toArray()
數(shù)組轉(zhuǎn)換成List --> Arrays.asList(new String[]{'AA','BB','CC'})
使用場景:生成一個不可更改的list
Arrays.asList
1.該方法適用于對象型數(shù)據(jù)的數(shù)組(String、Integer
...)
2.該方法不建議使用于基本數(shù)據(jù)類型的數(shù)組(byte,short,int,long,float,double,boolean
)
3.該方法將數(shù)組與List列表鏈接起來:當(dāng)更新其一個時,另一個自動更新
4.不支持add()、remove()、clear()等方法。用此方法得到的List的長度是不可改變的
List arr = Arrays.asList(new int[]{123,456})會把new int[]{123,456}整體看成一個元素,基本數(shù)據(jù)類型數(shù)組會被看成一個整體。可以寫成 List arr = Arrays.asList(123,456)
Set接口
Set接口中沒有額外定義新的方法。
比較HashSet、LinkedHashSet、TreeSet
同:都是Set接口的實(shí)現(xiàn)類,存放數(shù)據(jù)無序、不可重復(fù)
HashSet:Set接口的主要實(shí)現(xiàn)類,線程不安全,可以存放null值,數(shù)組+鏈表存儲數(shù)據(jù)
LinkedHashSet:HashSet的子類,遍歷其內(nèi)部數(shù)據(jù)時可以按照添加的順序遍歷,對于頻繁的遍歷操作,LinkedHashSet效率高于HashSet
TreeSet:數(shù)據(jù)是同一類的,可以按照添加對象的指定屬性,進(jìn)行排序。
無序性與不可重復(fù)性
無序性:不等于隨機(jī)性,存儲的數(shù)據(jù)在底層數(shù)組中并非按照數(shù)組索引的順序添加,而是根據(jù)數(shù)據(jù)的hash值決定。(數(shù)組中的存儲不是按照添加順序添加的)
不可重復(fù)性:先比較添加元素的hash值是否相同,相同按照equals()判斷是否重復(fù)
HashSet中元素的添加過程
向HashSet中添加元素a
1.先調(diào)用元素a所在類的hashCode()方法,計算a的哈希值。
2.此hash值通過散列函數(shù)計算出在HashSet底層數(shù)組中的存放位置 + 拉鏈法解決沖突
散列函數(shù) + 拉鏈法解決沖突 拉鏈法時要先比較hash值再按照equals()判斷是否重復(fù),不重復(fù)時再鏈上
要求:向Set中添加的數(shù)據(jù),其所在類的一定要重寫HashCode方法和equals方法,此兩個方法盡可能保持一致性。(相等的對象必須具有相同的hash值)
注意:
new HashSet()實(shí)際上是new了一個HashMap,向HashSet添加元素實(shí)際上是向HashMap添加元素,在HashSet中添加的元素相當(dāng)于是HashMap的key,value都指向一個對象(這個對象沒什么意義)
LinkedHashSet
LinkedHashSet作為HashSet的子類,在添加數(shù)據(jù)的同時,每個數(shù)據(jù)還維護(hù)了兩個引用指針,遍歷其內(nèi)部數(shù)據(jù)時可以按照添加的順序遍歷
TreeSet
要求:向TreeSet中添加的數(shù)據(jù),要求是相同類的對象作用:進(jìn)行排序
遍歷的時候會調(diào)用排序方法進(jìn)行自動排序。
自然排序(Comparable接口):比較兩個對象是否相同的標(biāo)準(zhǔn)為:compareTo()返回0,不再是equals()
定制排序(Comparator接口):比較兩個對象是否相同的標(biāo)準(zhǔn)為:compare()返回0,不再是equals()
Comparator com = new Comparator(){ //定制排序內(nèi)容 @override public int compare(Object o1,Object o2){} } TreeSet set = new TreeSet(com)
練習(xí)題
1.在List內(nèi)去除重復(fù)數(shù)字值,要求盡量簡單
HashSet常常用于過濾重復(fù)元素 --> set.addAll(list) --> return new ArrayList(set)
//Person類中重寫了hashCode()和equals()方法 HashSet set = new HashSet(); Person p1 = new Person(1001,"AA"); Person p2 = new Person(1002,"BB"); set.add(p1); set.add(p2); p1.name = "CC"; set.remove(p1);//remove時先計算hash值(此題由id和name共同計算所得),內(nèi)容變了hash值也變了 System.out.println(set);//1001,"CC" 1002,"BB" set.add(new Person(1001,"CC"));//原來的p1的hash值是按照1001,"AA"計算所得,此時算出來的應(yīng)該是新的hash值 System.out.println(set);//1001,"CC" 1002,"BB" 1001,"CC" set.add(new Person(1001,"AA")); //這里算出來是p1的hash值,hash值相同調(diào)用equals方法發(fā)現(xiàn)不同 System.out.println(set);//1001,"CC" 1002,"BB" 1001,"CC" 1001,"AA"
Map接口
Map實(shí)現(xiàn)類的結(jié)構(gòu)
HashMap:
作為Map的主要實(shí)現(xiàn)類,線程不安全,效率高??梢源鎯ey/value = null
LinkedHashMap:
在遍歷map元素時,可以按照添加的順序?qū)崿F(xiàn)遍歷。原因:在原有的HashMap底層結(jié)構(gòu)基礎(chǔ)上添加了一對指針,指向前一個和后一個元素。對于頻繁的遍歷操作,LinkedHashMap效率高于HashMap
TreeMap:
保證按照添加的key-value對進(jìn)行排序(key),實(shí)現(xiàn)排序遍歷,底層使用紅黑樹
Hashtable
:作為古老實(shí)現(xiàn)類,線程安全,效率低,不可以存儲key/value = null
Properties:
常用來處理配置文件,key-value都是String類型
Entry(key,value)
無序,不可重復(fù)(Set)
key無序,不可重復(fù),用set存儲。 --> 不可重復(fù),key所在的類要重寫quals()
和hashCode()
(HashMap為例)
value無序,可重復(fù) --> value所在的類要重寫equals,重寫是為了實(shí)現(xiàn)通過value找到key的方法
Map中的常用方法
增刪改
Object put(Object ket,Object value):
將指定key-value添加到(或修改key的值)當(dāng)前map對象
void putAll(Map m):
將m中的所有key-value對存放在當(dāng)前map中
Object remove(Object key):
移除指定key的key-value對,并返回value
void clear():
清空當(dāng)前的map中的數(shù)據(jù),map還在,只是里面沒數(shù)據(jù)了。map.size()不會報錯
查
Object get(Object key):
獲取指定key對用的value
boolean containsKey(Object key):
是否包含指定的key
boolean containsValue(Object key):
是否包含指定的key
int size():
返回map中鍵值對的個數(shù)
boolean isEmpty():
判斷當(dāng)前map是否為空
boolean equals(Object obj):
判斷當(dāng)前map和參數(shù)對象obj是否相等
遍歷
Set keySet():
返回所有key構(gòu)成的Set集合
Collection values():
返回所有value構(gòu)成的Collection集合
Set entrySet():返回所有key-value對構(gòu)成的Set集合,Set<Map.Entry<Character,Integer>> entry = map.entetSet()
//返回的是Collection之后就可以使用iterator迭代器 Set set = map.keySet(); Iterator iterator = set.iterator(); //遍歷所有的key-value Set entrySet = map.entrySet() Iterator iterator = entrySet.iterator(); while(iterator.hasNext()){ Object obj = iterator.next(); Map.Entry entry = (Map.Entry) obj; System.out.println(entry.getKey()+"--->"+entry.getValue()); } //寫法二 Set <Map.Entry<String,Integer>> entrySet = map.entrySet(); Iterator <Map.Entry<String,Integer>> iterator = entrySet.iterator(); while(iterator.hasNext()){ Map.Entry <String,Integer> entry = iterator.next(); String key = entry.getKey(); Integer value = entry.getValue(); }
HashMap
問題1:HashMap的底層實(shí)現(xiàn)原理?
JDK7:
//在實(shí)例化以后,底層創(chuàng)建了長度16的一維數(shù)組Entry[] table HashMap<E,E> map = new HashMap<E,E>(); //...可能已經(jīng)執(zhí)行過多次put... map.put(key1,value);
往map中添加鍵值對的過程
- 調(diào)用key1所在類的hashCode()計算key1哈希值,得到在Entry中的存放位置
- 檢查該位置是否有數(shù)據(jù)
- 沒有數(shù)據(jù),此時key1-value1添加成功
- 有數(shù)據(jù),比較key1和已存在的數(shù)據(jù)的哈希值
- 如果哈希值一樣,調(diào)用equals()方法,不相等則添加成功,相等用新的value替換舊的value。put有更新作用
- 如果哈希值不一樣,則添加成功
在不斷的添加過程中,默認(rèn)的擴(kuò)容方式:擴(kuò)容為原有容量的2倍,并將原有的數(shù)據(jù)復(fù)制。
JDK8相較于JDK7的不同點(diǎn)(類似ArrayList)
1.new HashMap():底層沒有創(chuàng)建一個長度為16的數(shù)組
2.首次調(diào)用put()方法時,底層創(chuàng)建長度為16的數(shù)組
3.jdk8 底層的數(shù)組是:Node[]
4.鏈表插入的方法(七上八下)
5.jdk7底層結(jié)構(gòu):數(shù)組+鏈表。jdk8中底層結(jié)構(gòu):數(shù)組+鏈表+紅黑樹。
當(dāng)數(shù)組的某一個索引位置上的元素以鏈表形式存在的數(shù)據(jù)個數(shù)>8且當(dāng)前數(shù)組的長度>64(若>8但是<64則擴(kuò)容),此時該索引位置上的所有數(shù)據(jù)使用紅黑樹存儲,
問題2:負(fù)載(加載)因子值的大小,對HashMap有什么影響?
HashMap的默認(rèn)容量16
HashMao的默認(rèn)加載因子0.75
threshold擴(kuò)容的臨界值=容量*填充因子=16 x 0.75=15
負(fù)載因子的大小決定了HashMap的數(shù)據(jù)密度
負(fù)載因子越大密度越大,發(fā)生碰撞的幾率越高,性能會下降
負(fù)載因子越小,越容易觸發(fā)擴(kuò)容,會浪費(fèi)空間
LinkedHashMap
LinkedHashMap是HashMap的子類,底層還是按照HashMap去存。
類似LinkedHashSet,在遍歷map元素時,可以按照添加的順序?qū)崿F(xiàn)遍歷。
LinkedHashMap中的內(nèi)部類多了befor和after指針
TreeMap
要求:向TreeMap中添加key-value,要求key必須是由同一個類創(chuàng)建的對象
排序:按照key進(jìn)行排序
自然排序(Comparable接口):
比較兩個對象是否相同的標(biāo)準(zhǔn)為:compareTo()返回0,不再是equals()
定制排序(Comparator接口):
比較兩個對象是否相同的標(biāo)準(zhǔn)為:compare()返回0,不再是equals()
//自然 TreeMap map = new TreeMap(); //添加的key類里重寫compareTo() //定制 Comparator com = new Comparator(){ //定制排序內(nèi)容 @override public int compare(Object o1,Object o2){} } TreeMap map = new TreeMap(com)
Properties
c類是Hashtable的子類,該對象用于處理屬性文件。
由于屬性文件里的key-value都是字符串類型,所以Properties里的key和value都是字符串類型。
存儲數(shù)據(jù)時,建議使用setProperty(String key,String value)方法和getProperty(String key)方法
需要在當(dāng)前項目中添加配置文件,F(xiàn)ile(手動添加后綴.properties)/Resource Bundle(自動添加后綴)
Properties pros = new Properties(); FileInputStream fis = new FileInputStream("配置文件的名字") //參數(shù)為流,加載流對用的文件 pros.load(fis); fis.close();
Collections工具類
Collections是一個操作Set、List和Map等集合的工具類。
Collections中提供了一系列靜態(tài)的方法對集合元素進(jìn)行排序、查詢和修改等操作,還提供了對集合對象設(shè)置不可變,對集合對象實(shí)現(xiàn)同步控制等方法
排序方法
reverse(List):
反轉(zhuǎn)List中元素的順序
shuffle(List):
對List集合元素進(jìn)行隨機(jī)排序
sort(List):
根據(jù)元素的自然順序?qū)χ付╨ist集合元素按升序排序
sort(List,Comparator):
根據(jù)指定的Comparator產(chǎn)生的順序?qū)ist集合元素進(jìn)行排序
swap(List,int,int):
將指定list集合中的i處元素和j處元素進(jìn)行交換
Object max/min(Collection):
根據(jù)元素的自然排序,返回給定集合中的最大/最小元素
Object max/min(Collection,Comparator):
根據(jù)Comparator指定的順序,返回集合中的最大/最小元素
int frequency(Collection,Object):
返回指定集合中指定元素出現(xiàn)的次數(shù)
void copy(List dest,List src):
將src中的內(nèi)容復(fù)制到dest中
boolean replaceAll(List list,Object oldVal,Objec newVal
):把List中所有的舊值改成新值
copy的注意事項
//************錯誤寫法1 //錯誤原因:需要滿足src.size()<= dest.size(),否則會報錯 List dest = new ArrayList(); //...一堆list.add() List dest = new ArrayList(); Collections.copy(dest,list); //************錯誤寫法2 //錯誤原因:傳參是指定造底層數(shù)組的長度,需要的dest.size是填了幾個 List dest = new ArrayList(); //...一堆list.add() List dest = new ArrayList(list.size()); Collections.copy(dest,list); //************正確寫法 List dest = new ArrayList(); //...一堆list.add() //asList數(shù)組轉(zhuǎn)化成List,這里的數(shù)組會默認(rèn)填充null List dest = Arrays.asList(new Object[list.size()]) Collections.copy(dest,list);
Collections常用方法:同步控制
Collections類中提供了多個synchronizedXxx(xxx)方法,將指定集合包裝成線程同步的集合,從而解決多線程并發(fā)訪問集合時的線程安全問題。
ArrayList和HashMap都是線程不安全的,如果要求線程安全可以使用synchronizedList(List list)和synchronizedMap(Map map)
//返回的List1為線程安全的List List list1 = Collections.synchronizedLisd(list);
總結(jié)
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Spring Boot 通過CORS實(shí)現(xiàn)跨域問題
這篇文章主要介紹了Spring Boot 通過CORS實(shí)現(xiàn)跨域,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09SpringBoot?DataSource數(shù)據(jù)源實(shí)現(xiàn)自動配置流程詳解
這篇文章主要介紹了SpringBoot?DataSource數(shù)據(jù)源實(shí)現(xiàn)自動配置流程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-10-10Java移位運(yùn)算符詳解實(shí)例(小結(jié))
這篇文章主要介紹了Java移位運(yùn)算符詳解實(shí)例(小結(jié)),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12Java+opencv3.2.0實(shí)現(xiàn)hough直線檢測
這篇文章主要為大家詳細(xì)介紹了Java+opencv3.2.0之hough直線檢測,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-02-02Mybatis update數(shù)據(jù)庫死鎖之獲取數(shù)據(jù)庫連接池等待
這篇文章主要介紹了Mybatis update數(shù)據(jù)庫死鎖之獲取數(shù)據(jù)庫連接池等待的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-07-07