天天看点

关于TreeSet

java.lang.Object

  |_ java.util.AbstractCollection<E>

    |_ java.util.AbstractSet<E>

        |_java.util.TreeSet<E>

TreeSet类声明如下:

public class TreeSet<E>

  extends AbstractSet<E>

  implements SortedSet<E>, Cloneable, java.io.Serializable

因为实现了SortedSet类,所以具有自然排序的功能。

TreeSet和HashSet相同的地方,就是集合里面不允许有重复的元素。自然排序情况下,一个TreeSet中只允许存放同一类型的多个元素,这里要求不是自定义的类。例如:

Set treeSet = new TreeSet();

  treeSet.add(new String("aaa"));

  treeSet.add(new String("bbb"));

  treeSet.add(new String("ccc"));

  System.out.println(treeSet);

结果输出为:

[aaa, bbb, ccc]

这时,treeSet.size()=3。而且,它是经过排序的输出。

如果有多个类的对象都加入到TreeSet集合中,就会发生异常。比如:

treeSet.add(new String("aaa"));

treeSet.add(new Integer(100));

System.out.println(treeSet);

发生异常:

Exception in thread "main" java.lang.ClassCastException: java.lang.String

at java.lang.Integer.compareTo(Integer.java:35)

at java.util.TreeMap.compare(TreeMap.java:1093)

at java.util.TreeMap.put(TreeMap.java:465)

at java.util.TreeSet.add(TreeSet.java:210)

at org.shirdrn.TreeSetTest.main(TreeSetTest.java:18)

而对于自定义的类,它的对象只能存放一个,而且实现类不需要实现Comparable接口。

但是,如果想要存放多个自定义的类的对象,不实现Comparable接口就会发生java.lang.ClassCastException异常。因此,想要能够进行客户化排序,必须实现比较器。

实现Comparable接口,就要实现compareTo()方法。而TreeSet又不存储相同的元素,这就要求自定义的类重写hashCode()和equals()方法:

class Person implements Comparable{

private String name;

private Integer age;

public Integer getAge() {

  return age;

}

public void setAge(Integer age) {

  this.age = age;

public String getName() {

  return name;

public void setName(String name) {

  this.name = name;

public boolean equals(Object o){

  if(this == o){

  return true;

  }

  if(! (o instanceof Person)){

  return false;

  final Person other = (Person)o;

  if(this.name.equals(other.getName()) && this.age.equals(other.getAge())){

  else{

public int hashCode(){

  int result;

  result = (name == null?0:name.hashCode());

  result = 37*result + (age == null?0:age.hashCode());

  return result;

public int compareTo(Object o){

  Person other = (Person)o;

  if(this.name.compareTo(other.getName()) > 0){

  return 1;

  if(this.name.compareTo(other.getName()) < 0){

  return -1;

  if(this.getAge().intValue() > other.getAge().intValue()){

  if(this.getAge().intValue() < other.getAge().intValue()){

  return 0;

测试一下:

  Person p1 = new Person();

  p1.setName("shirdrn");

  p1.setAge(new Integer(26));

  treeSet.add(p1);

  Person p2 = new Person();

  p2.setName("shirdrn");

  p2.setAge(new Integer(26));

  treeSet.add(p2);

实例化了2个Person对象,实际上他们是同一个,因此只输出一个:

[org.shirdrn.Person@c29b5984]

如果将p2的name设置为p2.setName("Keller"),则输出两个:

[org.shirdrn.Person@5462263d, org.shirdrn.Person@c29b5984]

由于在Person类中实现类了compareTo()方法,输出结果是排序的,首先按照name排序,然后再按照age排序:

while(it.hasNext()){

  Person p = (Person)it.next();

  System.out.println("name = "+p.getName()+" || age = "+p.getAge());

输出结果为:

name = Keller || age = 26

name = shirdrn || age = 26

name按照字母序排序。如果name相同,就按照age数字序排序。

TreeSet具有一些和HashSet类似的方法。

TreeSet的主要性质

1、TreeSet中不能有重复的元素;

2、TreeSet具有排序功能;

3、TreeSet中的元素必须实现Comparable接口并重写compareTo()方法,TreeSet判断元素是否重复 、以及确定元素的顺序 靠的都是这个方法;(这条性质比较重要,如果对TreeSet内部机制比较熟悉的话这条性质应该不难理解;如果读者不太理解的话可以参看以下这篇文章http://wlh269.iteye.com/blog/376430 )

4、对于java类库中定义的类,TreeSet可以直接对其进行存储,如String,Integer等(因为这些类已经实现了Comparable接口);

5、对于自定义类,如果不做适当的处理,TreeSet中只能存储一个该类型的对象实例,请看程序示例:

import java.util.*;

public class TreeSetDemo{

 public static void main(String args[]){

  TreeSet<Demo> tSet=new TreeSet<Demo>();

  Demo d1=new Demo(1,"abc");

  Demo d2=new Demo(2,"xyz");

  tSet.add(d1);

  tSet.add(d2);//如果有这条语句,运行程序时会抛出ClassCastException异常

                       //如果没有这条语句,程序会正常运行,并输出d1的内容

  Iterator itr=tSet.iterator();

  while(itr.hasNext()){

   Demo d=(Demo)itr.next();

   System.out.print(d.a+" "+d.b);

   System.out.println();

 } 

class Demo{

 int a;

 String b;

 public Demo(int a,String b){

  this.a=a;

  this.b=b;

 }

在TreeSet中存储自定义的类的实现方法

示例:

  Demo d3=new Demo(2,"uvw");

  tSet.add(d2);

  tSet.add(d3);

   System.out.print(d.a+" "+d.b);//注意此程序运行时会输出几个元素

class Demo implements Comparable{

  public int compareTo(Object o){

   Demo demo=(Demo)o;

  if(this.a>demo.a){

   return 1;

  }else if(this.a<demo.a){

   return -1;

  }else{

   return 0;

解析:上面程序会输出两个元素,并且是以a为判断标准按序输出的。当调用TreeSet的add()方法时,在TreeSet的内部会间接调用Demo的compareTo()方法、然后和TreeSet中已经存在的其他元素一一进行比较,在比较的过程中完成“判断是否重复”以及“排序”的功能:当在某次比较的过程中发现compareTo()返回0,就会认为待加入的元素已经存在于TreeSet中,返回-1或1的话就会根据TreeSet默认的比较器进行排序。

下面对程序进行修改,重写compareTo()方法,让TreeSet以a和b两个属性为依据来判断元素是否重复以及元素的顺序,请看下面的示例:

   System.out.print(d.a+" "+d.b);//注意这次输出的元素个数

if(this.a==demo.a&&this.b.equals(demo.b)){

  }else if(this.a>demo.a){

  }else {

继续阅读