java Set接口的实现类TreeSet 自然排序 定制排序
1.TreeSet 自然排序
- TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序排列
- 如果试图把一个对象添加到 TreeSet 时,则该对象的类必须实现 Comparable 接口。
- 实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即通过 compareTo(Object obj) 方法的返回值来比较大小。
//当向TreeSet中添加Person类,确定按照哪个属性排列。一般会通过多个属性的比较,避免片面返回零
@Override
public int compareTo(Object o) {
if(o instanceof Person) {
Person p = (Person)o;
// return this.name.compareTo(p.name);//从小到大
return -this.name.compareTo(p.name);//从大到小
}else {
return 0;
}
}
@Override
public int compareTo(Object o) {
if(o instanceof Person) {
Person p = (Person)o;
int i = this.name.compareTo(p.name);
if( i == 0 ) {
return this.age.compareTo(p.age);
}
}
return 0;
}
-
Comparable 的典型实现:
①BigDecimal、BigInteger 以及所有的数值型对应的包装类:按它们对应的数值大小进行比较
②Character:按字符的 unicode值来进行比较
③Boolean:true 对应的包装类实例大于 false 对应的包装类实例
④String:按字符串中字符的 unicode 值进行比较
⑥Date、Time:后边的时间、日期比前面的时间、日期大 -
向 TreeSet 中添加元素时,只有第一个元素无须比较compareTo()方法,后面添加的所有元素都会调用compareTo()方法进行比较。
-
因为只有相同类的两个实例才会比较大小,所以向 TreeSet 中添加的应该是同一个类的对象
-
对于 TreeSet 集合而言,它判断两个对象是否相等的唯一标准是:两个对象通过 compareTo(Object obj) 方法比较返回值
-
当需要把一个对象放入 TreeSet 中,重写该对象对应的 equals() 方法时,应保证该方法与 compareTo(Object obj) 方法有一致的结果:如果两个对象通过 equals() 方法比较返回 true,则通过 compareTo(Object obj) 方法比较应返回 0,即
compareTo()与hashCode()以及equals()三者保持一致
- String、包装类等的自然排序
/*
* 2.可以按照添加进集合的元素指定的顺序遍历,像String,包装类等默认顺序:从小到大
*/
@Test
public void testTreeSet1() {
Set set = new TreeSet<>();
set.add("JJ");
set.add(new String("MM"));
set.add("AA");
set.add("AA");
set.add("BB");
set.add("GG");
for(Object obj : set) {
System.out.println(obj);
}
}
- 当Person类没有实现Coparable接口时,向TreeSet中添加Person对象时,报ClassCastException
Set set = new TreeSet<>();
set.add(new Person("CC",12));
2.TreeSet 定制排序
- TreeSet的自然排序是根据集合元素的大小,进行元素升序排列。如果需要定制排序,比如降序排列,可通过Comparator接口的帮助。需要重写compare(T o1,T o2)方法。
- 利用int compare(T o1,T o2)方法,比较o1和o2的大小:如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示o1小于o2。
- 要实现定制排序,需要将实现Comparator接口的实例作为形参传递给TreeSet的构造器。
- 此时,仍然只能向TreeSet中添加类型相同的对象。否则发生ClassCastException异常。
- 使用定制排序判断两个元素相等的标准是:通过Comparator比较两个元素返回了0。
- demo
/*
* TreeSet的定制排序:
*
*/
@Test
public void testTreeSet2() {
//1. 创建一个实现了Comparator接口的对象
Comparator com = new Comparator() {
//向TreeSet中添加Customer类的对象,compare()方法中,
//指明按照Customer的哪个属性进行排序
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof Customer && o2 instanceof Customer ) {
Customer c1 = (Customer)o1;
Customer c2 = (Customer)o2;
int i = c1.getId().compareTo(c2.getId());
if(i == 0) {
return c1.getName().compareTo(c2.getName());
}
return i;
}
return 0;
}
};
//2.将此对象作为形参传递给TreeSet的构造器中
TreeSet set = new TreeSet(com);
//3.添加Comparator接口中的compare方法中涉及的类对象
set.add(new Customer("AA",1003));
set.add(new Customer("BB",1002));
set.add(new Customer("GG",1004));
set.add(new Customer("CC",1001));
set.add(new Customer("DD",1007));
for(Object obj : set) {
System.out.println(obj);
}
}
-
compareTo()与hashCode()以及equals()三者保持一致