---| Set接口 无序,不可以重复的集合
---| HashSet 线程不安全,存取速度快。底层是以hash表实现的。
---| TreeSet 红-黑树的数据结构,默认对元素进行自然排序(String)。如果在比较的时候两个对象返回值为0,那么元素重复。
1.HashSet
哈希表边存放的是哈希值。HashSet存储元素的顺序并不是按照存入时的顺序(和List显然不同) 是按照哈希值来存的所以取数据也是按照哈希值取得。
HashSet不存入重复元素的规则.使用hashcode和equals
HashSet到底是如何判断两个元素重复。
通过hashCode方法和equals方法来保证元素的唯一性,add()返回的是boolean类型
判断两个元素是否相同,先要判断元素的hashCode值是否一致,只有在该值一致的情况下,才会判断equals方法,如果存储在HashSet中的两个对象hashCode方法的值相同equals方法返回的结果是true,那么HashSet认为这两个元素是相同元素,只存储一个(重复元素无法存入)。
注意:HashSet集合在判断元素是否相同先判断hashCode方法,如果相同才会判断equals。如果不相同,是不会调用equals方法的。
哈希值相同equals为false的元素是怎么存储呢,就是在同样的哈希值下顺延(可以认为哈希值相同的元素放在一个哈希桶中)。也就是哈希一样的存一列。
图1:hashCode值不相同的情况
图2:hashCode值相同,但equals不相同的情况。
import java.util.HashSet; class Emp{ int id; String name; int salary; public Emp(int id,String name,int salary){ this.id=id; this.name=name; this.salary=salary; } @Override public String toString() { return " (编号 "+this.id+" 姓名 "+this.name+" 薪水 "+this.salary+" ) "; } @Override public int hashCode() {//重写hashcode方法 return this.id; } @Override public boolean equals(Object obj) {//重写equal方法,判断id和name一致时为true if (obj instanceof Emp) { Emp emp =(Emp) obj; return this.id==id&&this.name.equals(emp.name); } else { return false; } } } public class hashset02 { public static void main(String[] args) { HashSet set =new HashSet(); set.add(new Emp(110, "allen",1000)); set.add(new Emp(110, "leeleo",1000)); set.add(new Emp(110, "allen",1000)); System.out.println("重写方法后输出:"+set); } }
重写方法后输出:[ (编号 110 姓名 allen 薪水 1000 ) , (编号 110 姓名 leeleo 薪水 1000 ) ]
此处的set.add(new Emp(110, "allen",1000));和第一次加入对象的hashcode和equal比较后,都返回true。所以就无法存储。把equal方法屏蔽后输出:
[ (编号 110 姓名 allen 薪水 1000 ) , (编号 110 姓名 leeleo 薪水 1000 ) , (编号 110 姓名 allen 薪水 1000 ) ]
是由于第一次和第三次的hashcode虽然一致,但equal方法未重新,比较的是内存地址,返回的是false。所以可以存储。存储的方式如图二所示。
2.TreeSet
红-黑树
红黑树是一种特定类型的二叉树。红黑树算法的规则: 左小右大。既然TreeSet可以自然排序,那么TreeSet必定是有排序规则的。
1:让存入的元素自定义比较规则。
如果元素具备自然顺序的特性,那么就按照元素自然顺序的特性进行排序存储。
import java.util.TreeSet; public class Demo01 { public static void main(String[] args) { TreeSet set =new TreeSet (); set.add(4); set.add(2); set.add(9); set.add(5); set.add(8); set.add(1); System.out.println(set); } }
输出结果:[1, 2, 4, 5, 8, 9]
2.treeSet添加自定义元素:
treeSet要注意的事项:
1. 往TreeSet添加元素的时候,如果元素本身具备了自然顺序的特性,那么就按照元素自然顺序的特性进行排序存储。
2. 往TreeSet添加元素的时候,如果元素本身不具备自然顺序的特性,那么该元素所属的类必须要实现Comparable接口,把元素的比较规则定义在compareTo(T o)方法上。
3. 如果比较元素的时候,compareTo方法返回 的是0,那么该元素就被视为重复元素,不允许添加.(注意:TreeSet与HashCode、equals方法是没有任何关系。)
4. 往TreeSet添加元素的时候, 如果元素本身没有具备自然顺序 的特性,而元素所属的类也没有实现Comparable接口,那么必须要在创建TreeSet的时候传入一个比较器。
5. 往TreeSet添加元素的时候,如果元素本身不具备自然顺序的特性,而元素所属的类已经实现了Comparable接口, 在创建TreeSet对象的时候也传入了比较器那么是以比较器的比较规则优先使用。
如何自定义定义比较器: 自定义一个类实现Comparator接口即可,把元素与元素之间的比较规则定义在compare方法内即可
自定义比较器的格式 :
class 类名 implements Comparator{
}
推荐使用:使用比较器(Comparator)。