在工作中需要对一个集合去重,但是要保留之前的数据,当时想到了 new LinkedHashSet<>(tasks); 很方便的就解决了;
LinkedHashSet newTasks1 = new LinkedHashSet<>(tasks);
但是高兴的太早了,如果存在继承关系,如果只有继承类中的属性不一样,其他的都是一样,这样做任然会丢失一部分数据,
源码:
public LinkedHashSet(Collection extends E> c) {
super(Math.max(2*c.size(), 11), .75f, true);
addAll(c);
}
LinkedHashSet 是继承了HashSet super(Math.max(2*c.size(), 11), .75f, true) 调用的是
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
//扩容
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
很明显,他的底层实现是LinkedHashMap;
addAll 是
public boolean addAll(Collection extends E> c) {
boolean modified = false;
for (E e : c)
//add(e)调用的是hashSet中的add 方法, hashSet它的底层实现是HashMap
if (add(e))
modified = true;
return modified;
}
// hashSet中的add方法
public boolean add(E e) {
// private transient HashMap map;
return map.put(e, PRESENT)==null;
}
put 方法会去计算hash值,如果hashCode 相同,就不会添加
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null)
return putForNullKey(value);
int hash = hash(key);
int i = indexFor(hash, table.length);
for (Entry e = table[i]; e != null; e = e.next) {
Object k;
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;
}
我跟了一下源码,发现,他们的hashCode,是相同的,这就迷茫了,找了一下原因,是因为该实体类中的id是继承了另一个,所以会出现id不同,但是hashCode相同;测试了一些
比入:实体类
public abstract class AbsA {
private Long id;
}
public class B extends AbsA{
protected Integer userPermission;
}
@Data
public class TestC extends B{
private String title;
private String description;
}
test:
public class App {
public static void main(String[] args) {
List list = new ArrayList<>();
TestC c = new TestC();
TestC c2 = new TestC();
c.setId(1231231231L);
c2.setId(1231231232L);
c.setDescription("haha");
c2.setDescription("haha");
c.setTitle("zhangsan");
c2.setTitle("zhangsan");
list.add(c);
list.add(c2);
Set set = new HashSet<>(list);
System.out.println(set.size());
}
}
数据结果是 1;
下面提供一种去重的方法任然利用了set集合的特性;
private static List removeDuplicate(List tasks){
Set set = new HashSet<>();
List task = new ArrayList<>();
for (Iterator iter = tasks.iterator(); iter.hasNext();){
Task item = iter.next();
if (set.add(item.getId())){
task.add(item);
}
}
return task;
}