// 创建一个hashSet集合对象
HashSet<Object> hashSet = new HashSet<Object>();
查看HashSet的构造方法
//可以产出这里创建了HashMap<>()
public HashSet() {
map = new HashMap<>();
}
// 添加String类型元素
hashSet.add("a");
hashSet.add("b");
hashSet.add("c");
查看hashSet中的元素
// 查看源码,在AbstractCollection类中重写了toString方法
System.out.println(hashSet);
在AbstractCollection类中重写的toString方法
public String toString() {
Iterator<E> it = iterator();
if (! it.hasNext())
return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
E e = it.next();
sb.append(e == this ? "(this Collection)" : e);
if (! it.hasNext())
return sb.append(']').toString();
sb.append(',').append(' ');
}
}
结果
[a, b, c]
// 删除集合中的元素
hashSet.remove("b");
System.out.println(hashSet);
结果
[a, c]
public boolean remove(Object o) {
// 这里调用了map对象(HashMap类)的remove方法
return map.remove(o)==PRESENT;
}
public V remove(Object key) {
Node<K,V> e;
return (e = removeNode(hash(key), key, null, false, true)) == null ?
null : e.value;
}
static final int hash(Object key) {
int h;
// 如果对象不为null怎返回传入对象调用hashCode的返回值
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
final Node<K,V> removeNode(int hash, Object key, Object value,
boolean matchValue, boolean movable) {
Node<K,V>[] tab; Node<K,V> p; int n, index;
//1.因为前面调用了HashSet的add方法add方法中有调用了HashMap中的putVal方法
//在putVal方法中对table已经初始化过了默认为16
//因为传入的是字符串"b",他们调用hashCode方法的范围值和之前的添加的"b"是相同的
//所以这里可以得到之前添加的元素对应的索引
if ((tab = table) != null && (n = tab.length) > 0 &&
(p = tab[index = (n - 1) & hash]) != null) {
Node<K,V> node = null, e; K k; V v;
if (p.hash == hash &&
// 2.这里传入的字符串"b"的hash值和之前存入的"b"的hash值相同
// 传入对象和目标对象地址相同,所以这里把p的地址值赋值给node
// *但是如果出入对象和要删除的对象地址值不同,则需要调用传入对象的equals方法
// 如果返回的是true则把p的地址值赋给node
((k = p.key) == key || (key != null && key.equals(k))))
node = p;
else if ((e = p.next) != null) {
if (p instanceof TreeNode)
node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
else {
do {
if (e.hash == hash &&
((k = e.key) == key ||
(key != null && key.equals(k)))) {
node = e;
break;
}
p = e;
} while ((e = e.next) != null);
}
}
//3.由于node不为null,上面传入的matchValue为false所以这里进入if语句
//返回node,则remove方法返回node,在add方法中可以知道node的value是之前添加元素的value
//所以返回node它的value就是传入对象的PRESENT,比较之后返回true删除成功
if (node != null && (!matchValue || (v = node.value) == value ||
(value != null && value.equals(v)))) {
//node声明的时候属于Node类,但是Node和TreeNode没有子父类关系
//所以进入else if语句
if (node instanceof TreeNode)
((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
//又因为上面把p赋给了node所以这里node==p返回true
else if (node == p)
//把node后面的元素赋给当前数组索引的位置
//node对象中并没有给next赋值
//所以这里相当于把数据当前索引的位置 置为空,删除成功
tab[index] = node.next;
else
p.next = node.next;
++modCount;
--size;
afterNodeRemoval(node);
return node;
}
}
return null;
}
从上面的源码可以看出如果想要删除自定义对象需要重写该类的hashCode方法和eqals方法
创建一个Person类
public class Person {
private String id;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object obj) {
// 对传入的对象做判断是否属于Person类
// 否则有可能出现类型转换异常
if(obj instanceof Person) {
Person person = (Person)obj;
return id.equals(person.getId());
}
return false;
}
//重写toString方法方便观察对象的属性
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + "]";
}
}
public static void main(String[] args) {
// 创建一个hashSet集合对象
HashSet<Object> hashSet = new HashSet<Object>();
// 创建三个Person类对象
Person person1 = new Person();
Person person2 = new Person();
Person person3 = new Person();
// 给每个对象设置一个id的属性
person1.setId("1");
person2.setId("2");
person3.setId("3");
// 把对象添加进去
hashSet.add(person1);
hashSet.add(person2);
hashSet.add(person3);
System.out.println(hashSet);
// 创建一个新的对象并把id设为"3"
Person person = new Person();
person.setId("3");
hashSet.remove(person);
System.out.println(hashSet);
}
结果
[Person [id=1, name=null], Person [id=2, name=null], Person [id=3, name=null]]
[Person [id=1, name=null], Person [id=2, name=null]]