1. HashSet 集合
(1)HashSet 的概述
HashSet 的底层数据结构是哈希表(哈希表是一个元素为链表的数组)。HashSet 不是线程安全的,集合元素可以是null。当向HashSet 中存入一个元素时,HashSet 会调用该对象的HashCode()方法来得到该对象的HashCode值,然后根据HashCode值决定该对象在HashSet 中的存储位置。
(2)HashSet判断两个元素相等的标准:
两个对象的HashCode值相等,并且两个对象的equals方法的返回值也相等。
代码演示:
import java.util.Objects;
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
import java.util.HashSet;
public class Test {
public static void main(String[] args) {
HashSet<Person> set = new HashSet<>();
set.add(new Person("张三",21));
set.add(new Person("张三",22));
set.add(new Person("张三",21));
System.out.println(set);
}
}
执行结果:
重写了HashCode和equals方法后才能保证对象元素的唯一性。
2. LinkedHashSet 集合
(1)概述
LinkedHashSet 是底层数据是链表和哈希表。链表保证了数据的有序性,哈希表保证了数据的唯一性。
(2)特点:LinkedHashSet的存储顺序和取出的顺序是一样的,它是线程不安全的集合,运行速度快。
3. TreeSet 集合
(1)概述
TreeSet 集合继承于AbstractSet,所以它是一个Set集合,具有Set的属性和方法。
TreeSet基于TreeMap实现的。TreeSet中含有一个”NavigableMap类型的成员变量”m,而m实际上是”TreeMap的实例”。 底层的数据结构是红黑树(平衡二叉树)。
(2)特点
存入的元素唯一并且可以对元素排序。
排序方式有两种:自然排序和比较器排序。
如果要使用自然排序,那么对其中元素就要求实现Comparable 接口。
代码演示:
package com.westos.demo;
import java.util.Objects;
public class Person implements Comparable<Person>{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Person p) {
int num = this.age-p.age;
int num2 = num==0?this.name.compareTo(p.name):num;
return num2;
}
}
package com.westos.demo;
import java.util.TreeSet;
public class Test1 {
public static void main(String[] args) {
TreeSet<Person> set = new TreeSet<>();
set.add(new Person("张三",25));
set.add(new Person("李四",21));
set.add(new Person("王五",23));
set.add(new Person("王五",28));
for (Person person : set) {
System.out.println(person);
}
}
}
不写排序的异常:
执行结果:
4. HashCode和equals方法的面试题
● 问题: 如果两个对象的哈希值相同 p1.hashCode()==p2.hashCode() , 两个对象的equals一定返回true吗 p1.equals(p2) 一定是true吗?
正确答案:不一定
● 如果两个对象的equals方法返回的结果为true,两个对象的哈希值一定相同吗?
正确答案:一定
在 Java 应用程序执行期间,
1.如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
2.如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不 要求一定生成不同的整数结果。
两个对象不同(对象属性值不同) equals返回false=====>两个对象调用hashCode()方法哈希值相同
两个对象调用hashCode()方法哈希值不同=====>equals返回true
所以说两个对象哈希值无论相同还是不同,equals都可能返回true