前言:在java 中使用HashSet 结构来存放不重复的元素,但是HashSet 内部的元素时乱序的,存入和取出元素的顺序不能保证,那么有没有一种结构可以保证其顺序性,或者使用者可以自行决定顺序;LinkedHashSet 即实现了存取顺序的一致性;TreeSet可以让开发者自己定义元素的比较器,自行决定顺序;
1 使用:
// LinkedHashSet
Set<User> set = new LinkedHashSet<>(10, 0.75f);
User userOne = new User();
userOne.setId(1).setName("lisi").setAge(20);
set.add(userOne);
User userTwo = new User();
userTwo.setId(2).setName("wangwu").setAge(20);
set.add(userTwo);
set.remove(userTwo);
Iterator iterator1 = set.iterator();
while (iterator1.hasNext()) {
User user = (User) iterator1.next();
System.out.println("user = " + user);
}
// TreeSet
Set<User> set1 = new TreeSet<>(Comparator.comparingInt(User::getId));
User user1 = new User();
user1.setId(1).setName("lisi").setAge(20);
set1.add(userOne);
set1.add(userTwo);
set1.remove(userTwo);
Iterator iterator2 = set1.iterator();
while (iterator2.hasNext()) {
User user = (User) iterator2.next();
System.out.println("user = " + user);
}
2 过程:
2.1 构建:
LinkedHashSet:可以看到内部实际使用了LinkedHashMap进行数据存放
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
}
public LinkedHashSet() {
super(16, .75f, true);
}
public LinkedHashSet(Collection<? extends E> c) {
super(Math.max(2*c.size(), 11), .75f, true);
addAll(c);
}
// 使用HashSet 中 LinkedHashMap 作为数据结构进行存放
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
TreeSet:可以看到内部实际上使用TreeMap 进行数据存放
private transient NavigableMap<E,Object> m;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
TreeSet(NavigableMap<E,Object> m) {
this.m = m;
}
public TreeSet() {
this(new TreeMap<E,Object>());
}
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
public TreeSet(Collection<? extends E> c) {
this();
addAll(c);
}
public TreeSet(SortedSet<E> s) {
this(s.comparator());
addAll(s);
}
2.2 存入元素:
2.2.1 LinkedHashSet: 使用 LinkedHashMap 将元素e作为key ,new object() 作为value 进行数据存入
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
2.2.2 treeSet:使用 TreeMap 将元素e作为key ,new object() 作为value 进行数据存入
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
2.3 移除元素:
2.3.1 LinkedHashSet: 将元素从 LinkedHashMap 移除
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
2.3.2 treeSet: 将元素从 TreeMap 移除
public boolean remove(Object o) {
return m.remove(o)==PRESENT;
}
2.4 遍历元素:
2.4.1 LinkedHashSet:获取LinkedHashMap的keySet进行遍历:
public Iterator<E> iterator() {
return map.keySet().iterator();
}
final class LinkedKeySet extends AbstractSet<K> {
public final int size() { return size; }
public final void clear() { LinkedHashMap.this.clear(); }
public final Iterator<K> iterator() {
return new LinkedKeyIterator();
}
public final boolean contains(Object o) { return containsKey(o); }
public final boolean remove(Object key) {
return removeNode(hash(key), key, null, false, true) != null;
}
public final Spliterator<K> spliterator() {
return Spliterators.spliterator(this, Spliterator.SIZED |
Spliterator.ORDERED |
Spliterator.DISTINCT);
}
public final void forEach(Consumer<? super K> action) {
if (action == null)
throw new NullPointerException();
int mc = modCount;
for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
action.accept(e.key);
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
final class LinkedKeyIterator extends LinkedHashIterator
implements Iterator<K> {
public final K next() { return nextNode().getKey(); }
}
final LinkedHashMap.Entry<K,V> nextNode() {
LinkedHashMap.Entry<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
current = e;
next = e.after;
return e;
}
2.4.2:treeSet
public Iterator<E> iterator() {
return m.navigableKeySet().iterator();
}
// TreeMap KeySet
public Iterator<E> iterator() {
if (m instanceof TreeMap)
return ((TreeMap<E,?>)m).keyIterator();
else
return ((TreeMap.NavigableSubMap<E,?>)m).keyIterator();
}
Iterator<K> keyIterator() {
return new KeyIterator(getFirstEntry());
}
final class KeyIterator extends PrivateEntryIterator<K> {
KeyIterator(Entry<K,V> first) {
super(first);
}
public K next() {
return nextEntry().key;
}
}
Entry<K,V> next;
Entry<K,V> lastReturned;
int expectedModCount;
PrivateEntryIterator(Entry<K,V> first) {
expectedModCount = modCount;
lastReturned = null;
next = first;
}
// first 节点获取
final Entry<K,V> getFirstEntry() {
Entry<K,V> p = root;
if (p != null)
while (p.left != null)
p = p.left;
return p;
}
// 下一节点获取
final Entry<K,V> nextEntry() {
Entry<K,V> e = next;
if (e == null)
throw new NoSuchElementException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
next = successor(e);
lastReturned = e;
return e;
}
static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
if (t == null)
return null;
else if (t.right != null) {
Entry<K,V> p = t.right;
while (p.left != null)
p = p.left;
return p;
} else {
Entry<K,V> p = t.parent;
Entry<K,V> ch = t;
while (p != null && ch == p.right) {
ch = p;
p = p.parent;
}
return p;
}
}
3 总结:
3.1 LinkedHashSet 内部使用LinkedHashMap 将元素e 作为key 进行数据存放;TreeSet 内部使用TreeMap 将元素e 作为key 进行数据存放;
3.2 因为LinkedHashMap 内部元素通过prev 和next 指针维护了元素的有些性,进而保证了LinkedHashSet 存取元素的有序性;TreeSet 通过TreeMap 使用红黑树形结构,通过自定义元素的比较器 来保证元素存取元素的有序性;
3.3 LinkedHashSet&TreeSet 都不是线程安全的;