目录
一、LinkedHashSet的全面说明
- LinkedHashSet是HashSet的子类
- LinkedHashSet底层是一个LinkedHashMap,底层维护了一个数组+双向链表
- LinkedHashSet根据元素的hashCode值来决定元素的存储位置 ,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的。
- LInkedHashSet不允许添加重复元素。
- 只允许一个null值
二、LinkedHashSet源码解读
- 在LinkedHashSet中维护了一个hash表和双向链表(LinkedHashSet有head和tail)
- 每一个节点有before和after属性,这样可以形成双向链表
- 在添加一个元素时,先求hash值,再求索引,确定该元素在table的位置,然后将添加的元素加入到双向链表(如果已经存在,则不添加[原则和hashSet一样])
- 这样的话,遍历LinkedHashSet也能确保,插入顺序和遍历顺序一致
java
public class LinkedHashSetSource {
public static void main(String[] args) {
// LinkedHashSet的底层机制
Set set = new LinkedHashSet();
set.add(new String("AA"));
set.add(456);
set.add(456);
set.add(new Customer("张三", 1001));
set.add(123);
set.add("hello");
System.out.println("set=" + set);
/*
// 继承关系是在内部类完成
// HashMap.Node 说明Node是一个静态方法
// static class Node<K,V> implements Map.Entry<K,V>
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}*/
}
}
LinkedHashSet 加入顺序和取出元素/数据的顺序一致;
LinkedHashSet 底层维护的是一个LinkedHashMap(是HashMap的子类);
LinkedHashSet 底层结构 (数组table+双向链表);
第一次添加时,直接将 数组table 扩容到 16 ,临界值是12,存放的结点类型是 LinkedHashMap$Entry;
数组是 HashMapNode\[\] 存放的元素/数据是 LinkedHashMapEntry类型。
1.初始化数组长度为16,临界值为12
LinkedHashSet继承了HashSet
2.执行add方法中的add方法
3.执行put方法
4.计算hash值
5.table=null,扩容
6.创建新的结点,存放数据
7.返回null之前判断元素个数是否超过临界值
8.基本数据类型会被自动装箱
9.重复值和HashSet一样,不会被添加
10.双向链表示例
三、练习题
Car类(属性:name,price),如果name和price一样,则认为是相同元素,就不能添加。
代码实现:
java
public class LinkedHashSetExercise {
public static void main(String[] args) {
LinkedHashSet linkedHashSet = new LinkedHashSet();
linkedHashSet.add(new Car("奥拓", 1000)); // OK
linkedHashSet.add(new Car("奥迪", 300000)); // OK
linkedHashSet.add(new Car("法拉利", 1000000)); // OK
linkedHashSet.add(new Car("奥迪", 300000)); // 加入不了
linkedHashSet.add(new Car("保时捷", 7000000)); // OK
linkedHashSet.add(new Car("奥迪", 300000)); // 加入不了
for (Object o : linkedHashSet) {
System.out.println(o);
}
// Car{name='奥拓', price=1000.0}
// Car{name='奥迪', price=300000.0}
// Car{name='法拉利', price=1000000.0}
// Car{name='保时捷', price=7000000.0}
}
}
class Car {
private String name;
private double price;
public Car(String name, double price) {
this.name = name;
this.price = price;
}
// 注意:必须同时重写equals()和hashCode()方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Car car = (Car) o;
return Double.compare(car.price, price) == 0 && Objects.equals(name, car.name);
}
@Override
public int hashCode() {
return Objects.hash(name, price);
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}