天天看點

HashSet儲存自定義不重複對象

前言

首先要了解HashSet實作的機制,如果不了解,對于下面的操作也是一直半解,用過一次就忘,并沒有什麼意義。

HashSet實作原理

HashSet的實作内部其實是一個HashMap,HashMap的實作就是根據key來進行Hash變換映射到index下,如果index相同,會根據equal來判斷key是不是相同,不相同就在這個index使用連結清單存儲,key相同就覆寫原來的值。這樣就保證了key的唯一性。HashSet就是利用HashMap key的唯一性來實作集合内的資料不重複。這就是HashSet的原理了。

對象和字元串的不同

根據上面的HashSet的實作原理,Set裡面的元素都是HashMap的Key,而在HashMap中,Key預設使用的是字元串,為什麼不使用對象呢?是因為在HashMap中判斷Key是否相等的關鍵在于equal,Object預設的equal實作是使用==來判斷兩個對象是否相等的,這樣就會導緻String和普通的Object有很大的不同。String可以使用==來判斷兩個字元串是否相等,但是對于普通對象來說==隻是判斷對象的引用是否相等。這樣一來,目标就很明确了,要儲存自定義的不重複對象,必須要重寫對象的equal方法。

規約

再根據一條很有意義的規約:

重寫equal方法必須要重寫hashCode方法。

這樣就知道我們需要做什麼了:重寫equal方法和hashCode方法。

示例

下面例子指定一個屬性,自定義具有相同該屬性的對象隻能存儲一次,實作了不重複存儲。也就是去重。

package hashSetExample;

import java.util.HashSet;
import java.util.Set;

/**
 * Created by liusxg on 2017/3/9.
 */
public class RemoveDuplicateObj {
    static class Test {

        private String name;
        private Integer age;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }

        //重寫equal
        @Override
        public boolean equals(Object var1) {
            if (!(var1 instanceof Test)) {
                return false;
            }
            Test testVal1 = (Test) var1;
            if (testVal1.name == null) {
                return false;
            }
            return this.name == testVal1.getName();
        }
        //重寫hashCode
        @Override
        public int hashCode() {
            return this.name.hashCode();
        }

        //重寫toString,為列印友善
        @Override
        public String toString() {
            return "{"+this.name+","+this.getAge()+"}";
        }

    }
    public static void main(String[] args) {
        //測試資料
        Test test1 = new Test();
        test1.setName("小明");
        test1.setAge();
        Test test2 = new Test();
        test2.setName("小紅");
        test2.setAge();
        Test test3 = new Test();
        test3.setName("小明");
        test3.setAge();

        //測試代碼
        Set<Test> testSet = new HashSet<Test>();
        testSet.add(test1);
        testSet.add(test2);
        testSet.add(test3);

        System.out.println(testSet.size());
        System.out.println(testSet.toString());
    }
}
           

輸出結果:

2

[{小明,10}, {小紅,20}]

如果把equal和hashCode重寫注釋掉,輸出結果為:

3

[{小紅,20}, {小明,10}, {小明,30}]