目錄
- 一、Set集合
- 1.Set集合特點
- 2.Set集合分類
- 3.hashSet底層原理:(基于哈希表存儲數據的)
- 代碼演示
- 5.hashSet集合元素的去重操作(有些情況搞不動)
- 代碼演示
- 6.LinkedHashSet的底層原理(不常用,所以沒有代碼演示)
- 7.TreeSet的底層原理
- 代碼演示
一、Set集合
1.Set集合特點
無序:添加數據的順序和獲取出的數據順序不一致;不重復;不索引。
2.Set集合分類
- Hashset:無序、不重復、無索引
- LinkedHashSet:有序、不重復、無索引
- TreeSet:排序(從小到大派、不重復、無索引
注意:Set常用到的方法,基本上就是Collection提供的,自己幾乎沒有額外新增一些常用功能。
3.hashSet底層原理:(基于哈希表存儲數據的)
(1)哈希值:就是一個int類型的隨機值,java中每個對象都有一個哈希值。java中的所有對象,都可以調用Object類提供的hashCode方法,返回該對象的哈希值。
格式:
public int hashCode():
(2)對象哈希值的特點:
- 同一個對象多次調用hashCode()方法返回的哈希值是相同的。
- 不同的對象,它們的哈希值大概率不相等,但也有可能會相等(哈希碰撞).
(3)哈希表:
- JDK8之前:哈希表=數組+鏈表
- JDK8開始:哈希表=數組+鏈表+紅黑樹
- 哈希表是一種增刪改查數據,性能都比較好的數據結構。
(4)過程:(jDK8之前)
- 1.使用HashSet創建一個默認長度為16的數組,默認加載因子為0.75,數組名table。(注意:ArrayList創建的長度是10)
- 2.使用元素的哈希值對數組的長度做運算計算出應存入的位置。
- 3.判斷當前位置是否為null,如果是null直接存入
- 4.如果不為null,表示有元素,則調用equals方法比較,相等,不存;不相等,存入;
- 注意:JDK8之前,新元素存入數組,占老元素位置,老元素掛下面;JDK8之后,新元素直接掛在老元素下面。
- 5.如果存入的數據超過16*0.75,就會擴容為原來的2倍。
- JDK8之后,當鏈表長度超過8,且數組長度》=64時,自動將鏈表轉成紅黑樹。
紅黑樹:就是可以自平衡的二叉樹,紅黑樹是一種增刪改查數據性能相對較好的結構。
代碼演示
package com.item.demo1hashset;import java.util.*;
public class SetDemo1 {public static void main(String[] args) {Set<String> set =new HashSet<>();//一行經典的代碼set.add("java");set.add("java");set.add("鴻蒙");set.add("鴻蒙");set.add("電商設計");set.add("電商設計");set.add("新媒體");set.add("大數據");System.out.println(set);//[java, 新媒體, 鴻蒙, 電商設計, 大數據]System.out.println("============");Set<String> set1 =new LinkedHashSet<>();set1.add("java");set1.add("java");set1.add("鴻蒙");set1.add("鴻蒙");set1.add("電商設計");set1.add("電商設計");set1.add("新媒體");set1.add("大數據");System.out.println(set1);//[java, 鴻蒙, 電商設計, 新媒體, 大數據]System.out.println("============");Set<Double> set2 =new TreeSet<>();//一行經典的代碼set2.add(5.1);set2.add(5.1);set2.add(1.0);set2.add(2.0);set2.add(1.0);set2.add(3.0);set2.add(2.0);set2.add(5.4);System.out.println(set2);//[1.0, 2.0, 3.0, 5.1, 5.4]System.out.println("=============");String s1="acd";String s2="abc";System.out.println(s1.hashCode());//96386System.out.println(s1.hashCode());//96386System.out.println(s2.hashCode());//96354System.out.println(s2.hashCode());//96354}
}
5.hashSet集合元素的去重操作(有些情況搞不動)
需求:
創建一個存儲學生對象的集合,存儲多個學生對象,要求:多個學生對象的成員變量值相同時,我們就認為是同一個對象,要求只保留一個。
分析:
1.定義學生類,創建HashSet集合對象,創建學生對象。
2.把學生添加到集合。
結論:如果希望Set集合認為2個內容一樣的對象是重復的,必須重寫對象的hashCode()和equals()方法
代碼演示
主類代碼:
package com.item.demo1hashset;
import java.util.*;
public class SetDemo2 {public static void main(String[] args) {Student s1 = new Student("小王", 18, "北京", "123456");Student s2 = new Student("小李", 19, "北京", "987654");Student s3 = new Student("小王", 18, "北京", "123456");Student s4 = new Student("小李", 189, "北京", "987654");Set<Student> set = new HashSet<Student>();set.add(s1);set.add(s2);set.add(s3);set.add(s4);System.out.println(set);//在沒有寫equals和hashcode方法時,沒有去重!!!,因為這些在java里面每次創建一個新的對象,則地址不一樣,存入也不一樣。}
}
Student類代碼:
package com.item.demo1hashset;import java.util.Objects;public class Student {private String name;private int age;private String address;private String phone;public Student() {}public Student(String name, int age, String address, String phone) {this.name = name;this.age = age;this.address = address;this.phone = phone;}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;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}//這里寫入equals和hashCode方法@Overridepublic boolean equals(Object o) {//1.如果自己和自己比返回trueif (this == o) return true;//2.如果o為空或者o不是Student類型返回falseif (o == null || getClass() != o.getClass()) return false;//3.將o轉換成Student類型Student student = (Student) o;//4.比較屬性是否相同return age == student.age && Objects.equals(name, student.name) && Objects.equals(address, student.address) && Objects.equals(phone, student.phone);}@Overridepublic int hashCode() {return Objects.hash(name, age, address, phone);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", address='" + address + '\'' +", phone='" + phone + '\'' +'}'+"\n";}
}
6.LinkedHashSet的底層原理(不常用,所以沒有代碼演示)
依然是基于哈希表(數組、鏈表、紅黑樹)實現的。
但是,它的每個元素都額外的多了一個雙鏈表的機制記錄它前后元素的位置。
7.TreeSet的底層原理
基于紅黑樹實現的排序
注意:
1.對于數值類型:Integer,Double,默認按照數值本身的大小進行升序排序
2.對于字符串類型,默認按照首字符的編號升序排序
3.對于自定義類型如Student對象,TreeSet默認是無法直接排序的。
解決方法:
1.對象類實現一個Comparable比較接口,重寫compare方法,指定大小比較規則。
2.public TreeSet(Comparator c)集合自帶比較器Comparator對象,指定比較規則。
代碼演示
主類代碼:
package com.item.demo1hashset;import java.util.*;
public class SetDemo3 {public static void main(String[] args){Set<Teacher> teachers1=new TreeSet<>();teachers1.add(new Teacher("小王", 18,3245.2));teachers1.add(new Teacher("小李", 19,3345.3));teachers1.add(new Teacher("小孫", 20,3609.4));teachers1.add(new Teacher("小張", 18,2780.3));System.out.println(teachers1);//不修改就無法去重//解決方法2:Set<Teacher> teachers=new TreeSet<>(new Comparator<Teacher>() {@Overridepublic int compare(Teacher o1, Teacher o2) {return Double.compare(o2.getSalary(), o1.getSalary());//降序}});//繼續簡化//Set<Teacher> teachers=new TreeSet<>((o1, o2)->Double.compare(o2.getSalary(), o1.getSalary()));teachers.add(new Teacher("小王", 18,3245.2));teachers.add(new Teacher("小李", 19,3345.3));teachers.add(new Teacher("小孫", 20,3609.4));teachers.add(new Teacher("小張", 18,2780.3));System.out.println(teachers);//解決方法//1,對象類實現一個Comparable比較接口,重寫compare方法,指定大小比較規則。//2.public TreeSet(Comparator c)集合自帶比較器Comparator對象,指定比較規則。//解決方法2:Set<Teacher> teachers2=new TreeSet<>();teachers2.add(new Teacher("小王", 18,3245.2));teachers2.add(new Teacher("小李", 19,3345.3));teachers2.add(new Teacher("小孫", 20,3609.4));teachers2.add(new Teacher("小張", 18,2780.3));System.out.println(teachers);}
}
Teacher類代碼:
package com.item.demo1hashset;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Teacher implements Comparable<Teacher>{private String name;private int age;private double salary;@Overridepublic String toString() {return "Teacher{" +"name='" + name + '\'' +", age=" + age +", salary=" + salary +'}'+"\n";}//解決方法1:重寫方法,比較兩個對象的大小@Overridepublic int compareTo(Teacher o) {//按照年齡升序return this.getAge()-o.getAge();}
}