不包含重复元素的 collection
- 不允许添加重复的元素
- 没有索引
- 无序(插入和取出的顺序不一样与在TreeSet中自然排序不冲突)
本身没有什么方法,都是从父类Collection继承过来的
Set接口的实现类——HashSet
- 底层是哈希表结构 是一个HashMap的实例,而HashMap的底层是哈希表
- 不允许重复 重复的不会被添加,而不是覆盖原有值
- 无序
- ★HashSet里面的元素储存时由hashCode(根据对象的属性,方法,地址等)得到一个哈希值,把哈希值一样的元素存储到一起,所有哈希值按大小排列。所以在哈希的眼里是有序的,而在开发者看来是无序的。
如何过滤重复项:★【面试题】
- 通过调用hashCode和equals方法,来过滤重复项
- 先判断哈希值是否有一样的,如果没有,则直接添加
- 如果有一样的,则继续调用equals方法,判断是否相等,如果相等,则添加失败,如果不相等,则直接添加(普通类型和对象类型都一样)
- 而不是添加进去覆盖原来的元素
- 没有重写前: 哈希值是类名+地址号,equals比较的是地址号
对象类型,每新建一个新对象,不论里面的属性等是否一样,他们的哈希值都不一样,所以都能添加成功。实际开发中,希望若对象里面的属性等一样,则只添加一次,这就需要同过重新hashCode方法和equals方法来实现
重写hashCode方法 比较的是对象类的哈希值,全类名+地址号,每个对象都是不相同的
public int hashCode() {
// 乘以一个数,是为了避免两个不同的哈希值相加后相等的情况
return name.hashCode()+birthday.hashCode()*12;
}
重写equals方法 没重写前比较的是对象类型的地址号,即使属性值都一样也会存进去
public boolean equals(Object obj){
if(this==obj){ //判断地址是否相等
return true;
}
if(!(obj instanceof Employee)){ //判断引用名obj指向的对象是否为Employee类型
return false;
}
Employee e= (Employee)obj; //向下转型
if(e.name.equals(this.name)&&e.birthday==this.birthday){ //注意String用equals,数字类型的用==号
return true;
}
return false;
}
为什么要同时复写hashcode() 和 equals() 方法:
违反了相同对象必须具有相同散列码的原则
如果只复写了equals()那么当equals比较后相等时,为逻辑上相等,我们要认为他们是同一个对象,就必须让hashcode() 也相等,否则他们只是两个不同的对象
Set接口的实现类——TreeSet
底层是 二叉树结构, 可以实现对添加的元素进行自然排序, 不允许添加重复元素
二叉树结构(大的放右边,小的放左边,相等则不能存。实现从小到大的自然排序)
100
50 200
30 60 150 220
TreeSet 有两种排序方法
添加的参数必须具备比较性:八大包装类型,String类型都实现了Comparable 具备了比较性,所以我们自己定义的引用类型都要通过实现Comparable来拥有比较性。有以下两种方式(自己定义排序规则的方法)
// 方式一:对象类实现comparable接口,然后重写compareTo()方法
class Book implements Comparable
@Override
public int compareTo(Object o) {
if(this==o){ //this代表新添加的元素 注意与重新equals中this代表的不同
return 0;
}
Book b=(Book) o;
//数字类型可以直接比较
if(this.price>b.price){ //为什么这段程序中不用 instanceof this是新元素,instanceof用于判断
return 1;
}else if(this.price<b.price){
return -1;
}
//String类型比较用compareTo
return this.name.compareTo(b.name); //return 1 实现正序排列,return -1实现逆序排列
}
// 方式二:创建对象时通过匿名内部类实现 Comparator是一个接口 没有构造器,不能直接创建对象,只能创建实现类或匿名内部类来创建
TreeSet set=new TreeSet(new Comparator(){
public int compare(Object o1,Object o2){ //重写接口中compara方法
if(o1==o2){
return 0;
}
if(!(o1 instanceof Book)||!(o2 instanceof Book)){
return 1;(此处返回1或-1 都行,看自己怎么定义了)
}
Book b1=(Book)o1; //向下转型
Book b2=(Book)o2;
if( b1.getPrice()<b2.getPrice()){
return -1;
}
if(b1.getPrice()>b2.getPrice()){
return 1;
}
return b1.getName().compareTo(b2.getName());
}
});
###HashSet和TreeSet对比
底层结构 过滤重复项 特点 使用步骤
HashSet 哈希表 通过hashCode和equals 无序 相同
TreeSet 二叉树 通过比较,如果二者相等代表重复 自然排序 相同