Set集合

  • Set不重復(fù)集淮腾,無(wú)序。
  • Set不能通過(guò)下標(biāo)獲取指定的元素屉佳。因?yàn)樗詻](méi)有下標(biāo)谷朝。可以使用Iterator的方式迭代集合武花。若我們把List看成是有許多格子的盒子圆凰,那么Set就好像一個(gè)袋子。
  • 常用實(shí)現(xiàn)類:
    HashSet:使用散列算法(哈希)實(shí)現(xiàn)Set集合体箕。
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
 * Set集合 無(wú)序且不重復(fù)集
 * 常用實(shí)現(xiàn)類:
 *      HashSet:使用散列算法(哈希)實(shí)現(xiàn)Set集合
 */
public class SetTest {
    public static void main(String[] args) {
        //實(shí)例化一個(gè)HashSet集合
        Set<String> set = new HashSet<String>();
        /**
         * 向集合中添加元素也使用add
         * 但是add方法不是向集合末尾追加元素专钉,因?yàn)闊o(wú)序
         */
        set.add("One");
        set.add("Two");
        set.add("Three");
        /**
         * Set集合沒(méi)有g(shù)et(int index)方法
         * 我們不能像使用List那樣,根據(jù)下標(biāo)獲取元素累铅。
         * 想獲取元素需要使用Iterator
         */
        Iterator<String> it = set.iterator();
        while (it.hasNext()){
            String element = it.next();
            System.out.println(element);
        }
        /*
        * 宏觀上講:元素的順序和存放順序是不同的跃须。
        * 但是在內(nèi)容不變的前提下,存放順序是相同的(使用相同的算法)娃兽。
        * 但是我們使用的時(shí)候菇民,要當(dāng)做是無(wú)序的使用。
        * */
        //使用For-Each循環(huán)遍歷Set集合
        for (String element:set){
            System.out.println(element);
        }
    }
}

hashCode()方法

  • hashCode()方法是Object定義的方法换薄。所以每個(gè)類都會(huì)有該方法玉雾。若我們定義的類重寫了equals()方法,就要重寫hashCode()方法(Object提供的hashCode方法將返回該對(duì)象所在內(nèi)存地址的整數(shù)形式)轻要。
  • 若equals方法返回true复旬,那么這兩個(gè)對(duì)象應(yīng)該有相同的hashCode值,反過(guò)來(lái)不是必須的冲泥,當(dāng)時(shí)最好是這樣驹碍”谙眩可以提高諸如HashSet這樣的數(shù)據(jù)結(jié)構(gòu)的效率,一般情況下可以使用IDE提供的工具自動(dòng)生成hashCode方法志秃。

HashSet和hashCode方法的關(guān)系

  • HashSet是Set接口的實(shí)現(xiàn)類怔球,通過(guò)hash表的方式實(shí)現(xiàn);在將對(duì)象加入HashSet集合中時(shí)浮还,需要獲取對(duì)象的hashCode值通過(guò)hash算法索引到對(duì)應(yīng)的存儲(chǔ)空間竟坛。
  • 進(jìn)行hash算法確定存儲(chǔ)空間,當(dāng)通過(guò)contains方法判斷Set集合中是否包含某個(gè)對(duì)象是钧舌,需要首先根據(jù)對(duì)象的hashCode值索引到特定的空間担汤,然后再和空間中的對(duì)象調(diào)用equals方法進(jìn)行比較,這種查找方式不同于線性表的逐個(gè)比較洼冻,有很高的效率崭歧。
import java.util.HashSet;
import java.util.Set;
/**
 * hashCode
 */
public class HashTest {
    public static void main(String[] args) {
        Set<MyPoint> set = new HashSet<MyPoint>();
        set.add(new MyPoint(1,2));
        set.add(new MyPoint(3,4));
        /**
         * 查看新創(chuàng)建的對(duì)象是否在set中被包含
         * 雖然這里是新創(chuàng)建的對(duì)象,但是通過(guò)散列算法找到了位置后
         * 和里面存放的元素進(jìn)行equals比較為true撞牢,所以依然認(rèn)為
         * 是被包含的率碾。
         */
        System.out.println(set.contains(new MyPoint(1,2)));//true
    }
}
class MyPoint{
    private int x;
    private int y;
    public MyPoint(int x, int y) {
        this.x = x;
        this.y = y;
    }

    /**
     *equals()和hashCode()方法我們一般讓IDE幫我們自動(dòng)生成
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MyPoint point = (MyPoint) o;
        if (x != point.x) return false;
        return y == point.y;
    }
    /**
     * 若我們不重寫hashCode,那么使用的就是Object提供的屋彪,
     * 該方法是返回句柄(對(duì)象存放地址)所宰!換句話說(shuō),不同的對(duì)象hashCode不同
     * @return
     */
    @Override
    public int hashCode() {
        int result = x;
        result = 31 * result + y;
        return result;
    }
}

equals()方法和hashCode()方法對(duì)HashSet的影響

import java.util.HashSet;
import java.util.Set;
public class HashTest {
    public static void main(String[] args) {
        Set<MyPoint> set1 = new HashSet<MyPoint>();
        MyPoint p1 = new MyPoint(1,2);
        MyPoint p2 = new MyPoint(1,2);
        System.out.println("p1和p2是否為同一個(gè)對(duì)象"+(p1==p2));
        //重寫equals方法和hashCode方法時(shí)的結(jié)果:false
        //重寫equals方法未重寫hashCode方法時(shí)的結(jié)果:false
        //未重寫equals方法重寫hashCode方法時(shí)的結(jié)果:false
        System.out.println("p1和p2內(nèi)容是否一樣"+p1.equals(p2));
        //重寫equals方法和hashCode方法時(shí)的結(jié)果:true
        //重寫equals方法未重寫hashCode方法時(shí)的結(jié)果:true
        //未重寫equals方法重寫hashCode方法時(shí)的結(jié)果:false
        System.out.println("p1和p2的hashCode是否一樣"+(p1.hashCode()==p2.hashCode()));
        //重寫equals方法和hashCode方法時(shí)的結(jié)果:true
        //重寫equals方法未重寫hashCode方法時(shí)的結(jié)果:false
        //未重寫equals方法重寫hashCode方法時(shí)的結(jié)果:true
        set1.add(p1);
        set1.add(p2);
        System.out.println("hashset集合的元素?cái)?shù)"+set1.size());
        //重寫equals方法和hashCode方法時(shí)的結(jié)果:1
        //重寫equals方法未重寫hashCode方法時(shí)的結(jié)果:2
        //未重寫equals方法重寫hashCode方法時(shí)的結(jié)果:2
        System.out.println(set1);
        //重寫equals方法和hashCode方法時(shí)的結(jié)果:[MyPoint{x=1, y=2}]
        //重寫equals方法未重寫hashCode方法時(shí)的結(jié)果:[MyPoint{x=1, y=2}, MyPoint{x=1, y=2}]
        //未重寫equals方法重寫hashCode方法時(shí)的結(jié)果:[MyPoint{x=1, y=2}, MyPoint{x=1, y=2}]
        /**
         * 當(dāng)我們重寫了Point的equals方法和hashCode方法后我們發(fā)現(xiàn)
         * 雖然p1和p2是兩個(gè)對(duì)象撼班,但是當(dāng)我們將它們同時(shí)放入集合中時(shí)歧匈,
         * p2對(duì)象并沒(méi)有被添加進(jìn)集合。因?yàn)閜1在放入后砰嘁,p2放入時(shí)根據(jù)
         * p2的hashCode計(jì)算的位置中p2與該位置的p1的equals比較為true件炉,
         * HashSet認(rèn)為該對(duì)象已經(jīng)存在,所有拒絕將p2存入集合矮湘。
         */
        /**
         * 若我們不重寫MyPoint的hashCode方法斟冕,但是重寫了equals方法。
         * 兩個(gè)對(duì)象都可以放入HashSet集合中缅阳,因?yàn)閮蓚€(gè)對(duì)象具有不同的
         * hashCode值磕蛇,那么當(dāng)它們?cè)诜湃爰蠒r(shí)通過(guò)hashCode值進(jìn)行
         * 散列算法結(jié)果就不相同,那么它們會(huì)被放入集合的不同位置十办。
         * 位置不相同秀撇,HashSet則認(rèn)為他們不同,所有它們可以全部
         * 被存入集合向族。
         */
        /**
         * 若我們重寫了hashCode但是不重寫equals方法呵燕,
         * hashCode相同的情況下,在存放元素時(shí)件相,它們會(huì)在相同的位置再扭,
         * HashSet會(huì)在相同的位置上將后放入的對(duì)象與該位置其它對(duì)象依次
         * 進(jìn)行equals比較氧苍,若不相同,則將其存入泛范。
         * 在同一個(gè)位置若干元素让虐,這些元素會(huì)被放入一個(gè)鏈表中。
         * 由此可以看出罢荡。我們應(yīng)該盡量使得所有類的不同對(duì)象的hashCode
         * 值不同赡突。這樣才可以提高HashSet在檢索元素上的效率!
         * 否則可能檢索效率還不如List柠傍。
         */
        /**
         * 結(jié)論:
         *      使用HashSet集合存放元素時(shí)
         *      應(yīng)保證equals與hashCode方法在api上定義的要求
         * 存放規(guī)則:
         *      不同對(duì)象存放時(shí)麸俘,不會(huì)存放hashCode相同(存放位置相同)并且equals相同
         *      (內(nèi)容相同)的
         *      對(duì)象。缺一不可惧笛,否則HashSet不認(rèn)為它們是重復(fù)對(duì)象。
         */
    }
}
class MyPoint{
    private int x;
    private int y;
    public MyPoint(int x, int y) {
        this.x = x;
        this.y = y;
    }
    @Override
    public String toString() {
        return "MyPoint{" +
                "x=" + x +
                ", y=" + y +
                '}';
    }

    /**
     *equals()和hashCode()方法我們一般讓IDE幫我們自動(dòng)生成
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MyPoint point = (MyPoint) o;
        if (x != point.x) return false;
        return y == point.y;
    }
    /**
     * 若我們不重寫hashCode逞泄,那么使用的就是Object提供的患整,
     * 該方法是返回句柄(對(duì)象存放地址)!換句話說(shuō)喷众,不同的對(duì)象hashCode不同
     * @return
     */
    @Override
    public int hashCode() {
        int result = x;
        result = 31 * result + y;
        return result;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末各谚,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子到千,更是在濱河造成了極大的恐慌昌渤,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件憔四,死亡現(xiàn)場(chǎng)離奇詭異膀息,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)了赵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門潜支,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人柿汛,你說(shuō)我怎么就攤上這事冗酿。” “怎么了络断?”我有些...
    開(kāi)封第一講書人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵裁替,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我貌笨,道長(zhǎng)弱判,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任躁绸,我火速辦了婚禮裕循,結(jié)果婚禮上臣嚣,老公的妹妹穿的比我還像新娘。我一直安慰自己剥哑,他們只是感情好硅则,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著株婴,像睡著了一般怎虫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上困介,一...
    開(kāi)封第一講書人閱讀 51,190評(píng)論 1 299
  • 那天大审,我揣著相機(jī)與錄音,去河邊找鬼座哩。 笑死徒扶,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的根穷。 我是一名探鬼主播姜骡,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼屿良!你這毒婦竟也來(lái)了圈澈?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤尘惧,失蹤者是張志新(化名)和其女友劉穎康栈,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體喷橙,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡啥么,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了重慢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饥臂。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖似踱,靈堂內(nèi)的尸體忽然破棺而出隅熙,到底是詐尸還是另有隱情,我是刑警寧澤核芽,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布囚戚,位于F島的核電站,受9級(jí)特大地震影響轧简,放射性物質(zhì)發(fā)生泄漏驰坊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一哮独、第九天 我趴在偏房一處隱蔽的房頂上張望拳芙。 院中可真熱鬧察藐,春花似錦、人聲如沸舟扎。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)睹限。三九已至譬猫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間羡疗,已是汗流浹背染服。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留叨恨,地道東北人柳刮。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像特碳,于是被迫代替她去往敵國(guó)和親诚亚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容