HashSet
HashSet是Set接口其中的一个实现类
import java.util.HashSet;
public class HashCodeTest {
public static void main(String[] args) {
HashSet hashSet = new HashSet();
hashSet.add(12);
hashSet.add(4);
hashSet.add(35);
hashSet.add(12);
hashSet.add(27);
hashSet.add(9);
System.out.println(hashSet);
}
}
特点:
- 无序
- 元素唯一
底层原理
HashSet底层是一个哈希表(散列表),还有一个主数组+链表
以上面数据为例子:
特点:
- 必须含有HashCode()方法返回哈希码
- 必须含有equals()方法解决冲突
自定义引用类型
当我们没有在自定义类中没有定义HashCode()和equals()方法时
import java.util.HashSet;
public class HashCodeTest {
public static void main(String[] args) {
HashSet hashSet = new HashSet();
hashSet.add(new Person("张三",16));
hashSet.add(new Person("李四",17));
hashSet.add(new Person("小明",12));
hashSet.add(new Person("小华",15));
hashSet.add(new Person("小明",12));
hashSet.add(new Person("小红",17));
System.out.println(hashSet);
}
}
输出结果为:
[Person{name=‘李四’, age=17}, Person{name=‘小明’, age=12}, Person{name=‘小华’, age=15}, Person{name=‘小红’, age=17}, Person{name=‘张三’, age=16}, Person{name=‘小明’, age=12}]
并没有做到元素唯一的效果,所以这不是我们所需要的效果
当我们在自定义类中定义(重写)HashCode()和equals()方法后
import java.util.Objects;
public class Person {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
private String name;
private int age;
public Person(String name,int age) {
this.name = name;
this.age= age;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
结果为
[Person{name=‘小华’, age=15}, Person{name=‘张三’, age=16}, Person{name=‘小红’, age=17}, Person{name=‘李四’, age=17}, Person{name=‘小明’, age=12}]
达到我们预料的效果,这也刚好证明了HashCode()和equals()是HashSet()底层必需方法
在何时调用HashCode()和equals()方法?
可以在HashCode()和equals()方法加标记,结果为:
可以看到HashCode()被调用了6次,equals()被调用了一次
总结:
- 每次add元素,都会调用一次HashCode()f方法
- 只有在发生冲突时,才会调用equals()方法
扩展
我们知道HashSet()特点之一是无序,当我们需要有序输出元素是可以使用其子类LinkedHashSet
import java.util.LinkedHashSet;
public class HashCodeTest {
public static void main(String[] args) {
LinkedHashSet hashSet = new LinkedHashSet();
hashSet.add(new Person("张三",16));
hashSet.add(new Person("李四",17));
hashSet.add(new Person("小明",12));
hashSet.add(new Person("小华",15));
hashSet.add(new Person("小明",12));
hashSet.add(new Person("小红",17));
System.out.println(hashSet);
}
}
结果为:
[Person{name=‘张三’, age=16}, Person{name=‘李四’, age=17}, Person{name=‘小明’, age=12}, Person{name=‘小华’, age=15}, Person{name=‘小红’, age=17}]
可以看到LinkedHashSet可以有序输出元素,其底层原理跟HashSet原理基本一致