Java Set集合去重机制


关于java里面的集合,大家经常利用到Set集合没有重复数据的特性,来进行数据的去重,那么去重的原理是怎么样的呢?


最近面试了几个人,其间有聊到集合的东西,所以就顺便问了一下这个问题,但是都是只知道这么用,

而没有去看看底层代码的去重原理(而恰恰有可能这些基础原理会被用来设计其他一些场景实现),

所以在此文章记录一下,希望能帮助到一些人:


下面是Set集合的类图:




下面我们来跟踪一下执行的过程:

1. 首先我们实例化一个set对象

Set<8大基本类型> set = new HashSet<8大基本类型>();
set.add(8大基本类型);
2.add操作会调用HashSet中的add方法,实现如下:

public boolean add(E e) {
	return map.put(e, PRESENT)==null;
    }
3.HashSet中的add方法依赖了HashMap的put方法,实现如下:

public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {//每添加一个,则循环判断是否与map中的元素相等
            Object k;
            // 先判断hashcode是否一致,然后再判断值是否相等
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }

很明显上述操作对8种基本类型的数据+String型是有用的,但是如果想把去重的方式应用到复杂的对象呢,上述方式就还欠缺了一点了,

知道了执行顺序和原理了的话,就知道该如何去实现了!

下面就是重写对象User的实现,重写equals和hashCode方法!

测试类:

package com.test.set;

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

public class UniqueSet {

    /**
     * 
     * @param args
     */
    public static void main(String[] args) {

        User user1 = new User(1, "a");
        User user2 = new User(2, "b");
        User user3 = new User(3, "c");
        User user4 = new User(2, "b");

        Set<User> userSet = new HashSet<User>();
        userSet.add(user1);
        userSet.add(user2);
        userSet.add(user3);
        userSet.add(user4);
        // 输入结果 id=1 username=a  id=2 username=b  id=3 username=c  
        for (User u : userSet) {
            System.out.println("id=" + u.id + " " + "username=" + u.username);
        }
    }
}

实现类:

package com.test.set;

/**
 * 类描述:set集合针对String 类型和8大基础数据类型  过滤掉重复数据,
 * 如果存放的是其他类型对象,则需要重写hashCode方法和equals方法,
 * 当hashcode相等时(先执行hashCode方法),则会去执行equals方法,比较每个属性的值
 * 如果一致的话,则不会存进set,否则加入set集合 
 * 
 */
public class User {

    // id
    protected Integer id;
    // 名称
    protected String  username;

    //构造方法
    public User(Integer id, String username) {
        this.id = id;
        this.username = username;
    }

    /** 
     * 如果对象类型是User,先比较hashcode,一致的场合再比较每个属性的值
     */
    @Override
    public boolean equals(Object obj) {
        if (obj == null)
            return false;
        if (this == obj)
            return true;
        if (obj instanceof User) {
            User user = (User) obj;
            // if(user.id = this.id) return true; // 只比较id  
            // 比较每个属性的值 一致时才返回true 
            if (user.id == this.id && user.username.equals(this.username))
                return true;
        }
        return false;
    }

    /** 
     * 重写hashcode 方法,返回的hashCode不一样才再去比较每个属性的值
     */
    @Override
    public int hashCode() {
        // return id.hashCode();
        return id.hashCode() * username.hashCode();
    }
}



以上---------------------





评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值