关于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();
}
}
以上---------------------