TreeSet可以保证集合内的元素处于排序状态,底层是基于二叉树(红黑树)这种数据结构的。对于TreeSet中的一些方法,用一个示例来说明。
public class TreeSetDemo_01 {
public static void main(String[] args){
TreeSet nums = new TreeSet();
nums.add(5);
nums.add(2);
nums.add(10);
nums.add(-9);
//输出集合元素,可以发现元素已经处于排序状态
System.out.println(nums);
//取出集合中的第一个元素
System.out.println("集合中的第一个元素"+nums.first());
System.out.println("集合中的最后一个元素"+nums.last());
System.out.println("小于4的元素为:"+nums.headSet(4));
System.out.println("大于等于5的元素为:"+nums.tailSet(5));
System.out.println("大于等于-3,小于4的元素"+nums.subSet(-3, 4));
}
}
常见的常用的,也就first()和last()这几个。可以查看java API。
在TreeSet中,元素会被排序,有两种排序方式,一种是自然排序,一种是定制排序。
1. 自然排序
TreeSet中的元素会按照元素的compareTo()方法来比较元素之间的大小。然后按照元素的大小对元素进行升序排序。
java提供的Comparable接口,该接口就有compareTo()方法,该方法返回一个数值。当一个对象调用这个方法和另外一个对象进行比较的时候,obj1.compareTo(obj2)。返回0相等,返回正数obj1>obj2.否则obj2>obj1。
一般的常用的类都实现了comparable接口。如果是用户自定义的类,在试图把该类的对象添加到TreeSet中时,该类必须实现Comparable接口。否则会发生异常。
需要注意的是,在TreeSet中添加对象,必须添加同一个类别的对象。
在向TreeSet中添加元素时,重写compareTo()方法和equals()方法,要让这两个方法返回的结果一致。
class Z implements Comparable{
int age;
public Z(int age){
this.age = age;
}
@Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
return 1;
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
return true;
}
}
public class TreeSetDemo_02 {
public static void main(String[] args){
TreeSet set = new TreeSet();
Z z1 = new Z(6);
set.add(z1);
System.out.println(set.add(z1));
System.out.println(set);
((Z)set.first()).age = 9;
System.out.println(((Z)set.last()).age);
}
}
当向TreeSet中添加第二个相同的元素时,由于conpareTo()方法一致返回1,即使equals()方法返回true。任然将两个相同的对象添加到了集合里面,改变其中一个元素的属性,另一个元素的属性也会随之改变。因为他们就是同一个对象。
写一个正确的例子再一次说明TreeSet的用法。
import java.util.TreeSet;
class Person implements Comparable{
private int age;
private String name;
public Person(){
}
public Person(String name, int age){
this.name = name;
this.age = age;
}
public boolean equals(Object obj){
if(this == obj){
return true;
}
if(obj!=null && obj.getClass() == Person.class){
Person p = (Person)obj;
if(this.name.equals(p.name) && this.age == p.age){
return true;
}
}
return false;
}
public int compareTo(Object obj){
Person p = (Person)obj;
//如果只比较年龄,写法就非常简洁了。
System.out.println(this.name+"compare to"+p.name);
return this.age > p.age ? 1 : this.age < p.age ? -1 : 0;
}
public String toString(){
return "[age:"+this.age+" name:"+this.name+"]";
}
}
public class TreeSetDemo_03 {
public static void main(String[] args){
TreeSet ts = new TreeSet();
ts.add(new Person("zhang",10));
ts.add(new Person("wang",12));
ts.add(new Person("li", 6));
ts.add(new Person());
System.out.println("第二次添加无参数Person对象,成功?"+ts.add(new Person()));
System.out.println(ts);
}
}
输出结果:
zhangcompare tozhang
wangcompare tozhang
licompare tozhang
nullcompare tozhang
nullcompare toli
nullcompare tozhang
nullcompare toli
nullcompare tonull
第二次添加无参数Person对象,成功?false
[[age:0 name:null], [age:6 name:li], [age:10 name:zhang], [age:12 name:wang]]
可以发现,当向TreeSet中添加重复元素的时候,添加不成功,保证了TreeSet中元素的唯一性。
如果要实现定制排序,可以通过Comparator接口的compare(T o1, T o2)方法,来比较两个元素的大小。返回正数表示o1>o2,相等为0,小于为负。对于上面的例子,如果要实现降序排列,可以借助Comparator接口来实现。
import java.util.Comparator;
import java.util.TreeSet;
class Person1{
int age;
public Person1(){
}
public Person1(int age){
this.age =age;
}
public String toString(){
return "M[age:"+this.age+"]";
}
}
public class TreeSetDemo_04 {
public static void main(String[] args){
TreeSet ts = new TreeSet(new Comparator()
{
@Override
public int compare(Object o1, Object o2) {
// TODO Auto-generated method stub
Person1 p1 = (Person1)o1;
Person1 p2 = (Person1)o2;
return p1.age > p2.age ? -1 : p1.age < p2.age ? 1:0;
}
});
ts.add(new Person1(5));
ts.add(new Person1(-3));
ts.add(new Person1(9));
System.out.println(ts);
}
}
创建一个Comparator接口的匿名内部类的对象,该对象用来负责集合ts的排序。