Java基础23-集合类2(Set接口,Iterator迭代器)
一、Set接口簡(jiǎn)介
根據(jù)API,Set接口是一個(gè)不包含重復(fù)元素的 collection。更確切地講,set 不包含滿足 e1.equals(e2) 的元素對(duì) e1 和 e2,并且最多包含一個(gè) null 元素。正如其名稱所暗示的,此接口模仿了數(shù)學(xué)上的 set 抽象。
?
二、Set接口特性
1.不允許重復(fù)(HashCode/equals方法)
2.不記錄添加順序(沒(méi)有添加順序,但不代表元素排列沒(méi)有順序)
?三、實(shí)現(xiàn)類
(1).HashSet
此類實(shí)現(xiàn) Set 接口,由哈希表(實(shí)際上是一個(gè) HashMap 實(shí)例)支持。它不保證 set 的迭代順序;特別是它不保證該順序恒久不變。此類允許使用 null 元素。?
1.常用方法
public static void main(String[] args) {Set<String> set=new HashSet<>();set.add("o");set.add("0");set.add("-1");set.add("s");//以下的有序排列是因?yàn)樗鼈兊膆ashcode是有序的,是根據(jù)hashcode來(lái)進(jìn)行排序的set.add("a");set.add("b");set.add("c");set.add("d");set.add("e");//相同的元素hashcode相同,后邊這個(gè)會(huì)將前邊的覆蓋掉set.add("0");System.out.println(set);//[0, a, b, s, c, -1, d, e, o]Set<String> set1=new HashSet<>();set1.add("6");set1.add("8");//將set1里邊的值放到set中 set.addAll(set1);//set.clear();for (String ele : set) {System.out.println(ele);//0 a b s c -1 d e 6 8 o }System.out.println("--------------");Iterator<String> it = set.iterator();while(it.hasNext()) {System.out.println(it.next());}System.out.println(set.remove("-1"));//true set.removeAll(set1);System.out.println(set);//[0, a, b, s, c, d, e, o] } HshSet是set接口最常用的實(shí)現(xiàn)類,底層采用了哈希表(散列/hash)算法
其底層其實(shí)也是一個(gè)數(shù)組,存在的意義是提供查詢速度,插入速度以比較快,但是適用于少量數(shù)據(jù)的插入操作
?2.在HshSet中如何判斷兩個(gè)對(duì)象是否相同的問(wèn)題
1).兩個(gè)對(duì)象的equals比較相等,返回true則說(shuō)明相同對(duì)象
?2).兩個(gè)對(duì)象的hashcode方法返回值相等
?對(duì)象的hashcode值決定了在哈希表中的存儲(chǔ)位置
3. 當(dāng)往hashset集合中添加新的對(duì)象時(shí),先判斷該對(duì)象中的hashcode
- 如果不等:直接把新的對(duì)象存儲(chǔ)到hashcode指定的位置
- 如果相等:再繼續(xù)判斷新對(duì)象和集合對(duì)象中的equals做比較
若hashcode相同,equals為false:非常麻煩,存儲(chǔ)在之前對(duì)象同槽位的鏈表上(操作比較麻煩)
3.對(duì)象的hashcode和equals方法的重要性:
?每一個(gè)存儲(chǔ)到hash表中的對(duì)象,都得提供hashcode和equals方法,用來(lái)判斷是否是同一個(gè)對(duì)象
?存儲(chǔ)在哈希表中的對(duì)象,都應(yīng)該覆蓋equals方法和hashcode方法并且保證equals相等的時(shí)候,hashcode也應(yīng)該相等
(2).LinkedHashSet
此實(shí)現(xiàn)與 HashSet 的不同之外在于,后者維護(hù)著一個(gè)運(yùn)行于所有條目的雙重鏈接列表。此鏈接列表定義了迭代順序,即按照將元素插入到 set 中的順序(插入順序)進(jìn)行迭代。注意,插入順序不 受在 set 中重新插入的 元素的影響。(如果在 s.contains(e) 返回 true 后立即調(diào)用 s.add(e),則元素 e 會(huì)被重新插入到 set s 中。)?
Set<String> set2=new LinkedHashSet<>();set2.add("o");set2.add("0");set2.add("-1");set2.add("s");set2.add("a");set2.add("b");set2.add("c");set2.add("d");set2.add("e");//鏈表算法(保證添加順序,但無(wú)索引)System.out.println(set2);//[o, 0, -1, s, a, b, c, d, e](3)TreeSet
基于 TreeMap 的 NavigableSet 實(shí)現(xiàn)。使用元素的自然順序?qū)υ剡M(jìn)行排序,或者根據(jù)創(chuàng)建 set 時(shí)提供的 Comparator 進(jìn)行排序,具體取決于使用的構(gòu)造方法。
主要是用于排序,但實(shí)際開(kāi)發(fā)中主要是在數(shù)據(jù)庫(kù)中進(jìn)行排序等操作。
TreeSet也不能存放重復(fù)對(duì)象,但是TreeSet會(huì)自動(dòng)排序,如果存放的對(duì)象不能排序則會(huì)報(bào)錯(cuò),所以存放的對(duì)象必須指定排序規(guī)則。排序規(guī)則包括自然排序和自定義排序。
①自然排序:TreeSet要添加哪個(gè)對(duì)象就在哪個(gè)對(duì)象類上面實(shí)現(xiàn)java.lang.Comparable接口,并且重寫comparaTo()方法,返回0則表示是同一個(gè)對(duì)象,否則為不同對(duì)象。
②自定義排序:建立一個(gè)第三方類并實(shí)現(xiàn)java.util.Comparator接口。并重寫方法。定義集合形式為TreeSet ts = new TreeSet(new 第三方類());
//TreeSet集合底層才有紅黑樹(shù)算法,會(huì)對(duì)存儲(chǔ)的元素默認(rèn)使用自然排序(從小到大);
//注意:必須保證TreeSet集合中的元素對(duì)象是相同的數(shù)據(jù)類型,否則報(bào)錯(cuò)
//在TreeSet的自然排序中,認(rèn)為如果兩個(gè)對(duì)象作比較的compareTo方法返回的是0,則認(rèn)為是同一個(gè)對(duì)象
①自然排序
實(shí)現(xiàn)Comparable接口
重寫hashcode和equals方法
重寫compareTo方法
TreeSet<Person> set4=new TreeSet();set4.add(new Person("路飛",18));set4.add(new Person("索隆",26));set4.add(new Person("山治",23));set4.add(new Person("娜美",22));System.out.println(set4);//[Person [name=路飛, age=18], Person [name=娜美, age=22], Person [name=山治, age=23], Person [name=索隆, age=26]]?
三、Iterator迭代器
對(duì) collection 進(jìn)行迭代的迭代器。迭代器取代了 Java Collections Framework 中的 Enumeration。迭代器與枚舉有兩點(diǎn)不同:
- 迭代器允許調(diào)用者利用定義良好的語(yǔ)義在迭代期間從迭代器所指向的 collection 移除元素。
- 方法名稱得到了改進(jìn)。?
它 提供一種方法訪問(wèn)一個(gè)容器(container)對(duì)象中各個(gè)元素,而又不需暴露該對(duì)象的內(nèi)部細(xì)節(jié)。 從定義可見(jiàn),迭代器模式是為容器而生。很明顯,對(duì)容器對(duì)象的訪問(wèn)必然涉及到遍歷算法。
?
public class IteratorDemo { /*把集合中的元素一個(gè)一個(gè)的遍歷出來(lái)。* 迭代器對(duì)象* * */public static void main(String[] args) {List list=new ArrayList();list.add("a");list.add("b");list.add("c");//方式1:for循環(huán)//方式2:for-each 增強(qiáng)for循環(huán)//for(元素類型 ele:數(shù)組名/Iterable實(shí)現(xiàn)類對(duì)象)for (Object object : list) {System.out.println(object);}//方式3:使用while循環(huán)操作迭代器IteratorIterator it=list.iterator();while(it.hasNext()) {System.out.println(it.next());}//方式3:for循環(huán)操作迭代器for(Iterator it1=list.iterator();it.hasNext();) {System.out.println(it.next());}//深入分析foreach和迭代器//1.foreach操作數(shù)組:底層依然是采用for循環(huán)+索引來(lái)獲取數(shù)組元素int[] arr= {1,2,3};for (int i : arr) {System.out.println(i);}//2.foreach可以操作iterable的實(shí)例:底層其實(shí)采用的iterator迭代器for (Object object : list) {System.out.println(object);if("c".equals(object)) {list.remove(object);//并發(fā)修改異常 java.util.ConcurrentModificationException//當(dāng)使用迭代器時(shí),當(dāng)前線程A中,會(huì)單獨(dú)創(chuàng)建一個(gè)新的線程B//A線程負(fù)責(zé)繼續(xù)迭代,B線程負(fù)責(zé)去刪除//B線程每次都會(huì)去檢查和A線程中的元素是否個(gè)數(shù)相同,如果不是則報(bào)錯(cuò),并發(fā)修改異常//如何解決呢?//不要使用集合對(duì)象的刪除方法//在collection接口中存在刪除指定元素的方法boolean remove//該方法只能從集合中刪除元素,不能把迭代器中指定的元素進(jìn)行刪除//正確 -使用iterator中的remove方法 }}while(it.hasNext()) {Object ele=it.next();if("c".equals(ele)) {//list.remove(ele);//錯(cuò)誤,不能使用集合對(duì)象的removeit.remove();//正確,保證了兩個(gè)線程的同步 }System.out.println(ele);}//結(jié)論:直接使用foreach迭代數(shù)組和集合元素即可,簡(jiǎn)單。//當(dāng)需要遍迭代集合元素,邊刪除指定的元素時(shí),此時(shí)只能使用迭代器 } }?
轉(zhuǎn)載于:https://www.cnblogs.com/LuckyGJX/p/9116735.html
總結(jié)
以上是生活随笔為你收集整理的Java基础23-集合类2(Set接口,Iterator迭代器)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 一站式机器学习平台TI-ONE是什么?—
- 下一篇: vue java 使用AES 前后端加密