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