特点
无序、值唯一
实现类
HashSet类
特点
无序
数据结构
创建HashSet时,其构造方法创建维护了一个HashMap来进行存储,元素值保存在HashMap的key位置
常用方法
其常用方法基本与List接口相同,详情可查看我的上一篇博客“Java学习日记——List接口”
LinkedHashSet
特点
有序
数据结构
创建LinkedHashSet时,其构造方法调用父类构造方法,在内部创建维护了一个LinkedHashMap,用于维持元素的有序性
TreeSet类
特点
可排序
数据结构
创建TreeSet时,其构造方法创建了一个TreeMap,用于保存元素。由于TreeMap可以自动排序,所以TreeSet中的元素也按照排序特点保存。
TreeSet对其可排序举例如下
//Book类
import java.util.Objects;
public class Book implements Comparable<Book>{
private String bookName; // 书名
private int pageSize; // 页数
private double price; // 价格
public Book() {
}
public Book(String bookName, int pageSize, double price) {
super();
this.bookName = bookName;
this.pageSize = pageSize;
this.price = price;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"bookName='" + bookName + '\'' +
", pageSize=" + pageSize +
", price=" + price +
'}';
}
@Override
public int hashCode() {
return Objects.hash(this.bookName,this.pageSize,this.price);
}
@Override
public boolean equals(Object obj) {
if (this==obj){
return true;
}
if (obj instanceof Book){
Book book = (Book)obj;
return this.bookName.equals(bookName)&&this.pageSize== book.pageSize&&this.price== book.price;
}
return false;
}
@Override
public int compareTo(Book o){
if (this.pageSize==o.pageSize){
return this.bookName.compareTo(o.bookName);
}
return this.pageSize-o.pageSize;
}
}
//测试类demo
import java.util.Comparator;
import java.util.HashSet;
import java.util.TreeSet;
public class demo {
public static void main(String[] args) {
TreeSet<Book> bookSet=new TreeSet<>(new Comparator<Book>() {
@Override
public int compare(Book o1, Book o2) {
if (o1.getPrice()>o2.getPrice()){
return 1;
} else if (o1.getPrice()<o2.getPrice()) {
return -1;
}
return 0;
}
});
bookSet.add(new Book("我的高密", 1901, 177.5));
bookSet.add(new Book("射雕英雄传", 2374, 66.51));
bookSet.add(new Book("平凡的世界", 2110, 51.75));
bookSet.add(new Book("葫芦娃大战奥特曼", 1875, 135.49));
bookSet.add(new Book("鲁滨逊漂流记", 3694, 99.99));
bookSet.add(new Book("海底两万里", 1120, 33.15));
bookSet.add(new Book("海底两万里一千里", 1120, 34.15));
for (Book book:bookSet){
System.out.println(book);
}
}
}
/*
输出内容
Book{bookName='海底两万里', pageSize=1120, price=33.15}
Book{bookName='海底两万里一千里', pageSize=1120, price=34.15}
Book{bookName='平凡的世界', pageSize=2110, price=51.75}
Book{bookName='射雕英雄传', pageSize=2374, price=66.51}
Book{bookName='鲁滨逊漂流记', pageSize=3694, price=99.99}
Book{bookName='葫芦娃大战奥特曼', pageSize=1875, price=135.49}
Book{bookName='我的高密', pageSize=1901, price=177.5}
*/
常见问题
Set集合如何过滤重复元素?
1.调用元素HashCode方法来获取元素的哈希值
2.通过哈希值在对于的集合中查找是否有相同的哈希值
3.若找到相同的哈希值,则调用equals()方法来对元素的内容进行比较,若不同则添加,相同则不添加
4.若找不到相同的哈希值,则直接将该元素添加
通过以上四个步骤,确保了Set集合中无重复元素
为什么重写hashCode()时,必须重写equals()?
在上一个问题回答中提到,在Set集合中进行存储新元素时,首先通过调用元素的hashcode()方法来在要插入的集合中进行查找,如果在集合中未查找到该哈希值,则直接存储。但是对于哈希值来说他是根据元素来计算出来的整型数字,而int是有范围的,它的范围是-2,147,483,648(-2^31)到 2,147,483,647(2^31 - 1),共计约 21 亿个不同的整数。但是元素在理论上是无限的,所以int型数字如果一一匹配各个元素,肯定会有两个甚至多个元素拿去到的int型数字是相同的,也就是说,一个hashcode值可能对应多个(甚至是无数个)元素。例如:
public static void main(String[] args) {
String s1="通话";
String s2="重地";
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
}
/*
输出
1179395
1179395
*/
可见s1和s2的哈希值是相同的,当一个集合中存入了s1内容为“通话”时,在未重写equals方法时,再想存入s2时,JVM直接判断集合中有相同的哈希值,则认为元素相同,为了保持集合的不重复性,则不会存储s2,所以需要对equals方法进行重写来判断输入的s2与s1的内容是否相同。
为什么会产生哈希冲突?
在回答上述问题中已经提到