在TreeSet中,元素的添加需要进行比较大小。但是,集合中的元素都是引用类型的数据没有大小可言,这时我们就可以针对元素的某一个属性比较大小。如果这个元素的属性值大于那个元素的属性值,我们就可以认为这个元素比那个元素大,这样就可以将对象存入TreeSet中了。
有两种方式可以解决这个问题:
1.定义要放入TreeSet中的对象的类时实现Comparable接口。
例如,要将Person对象放入TreeSet中,那么在定义Person类时首先要声明实现Comparable接口,然后实现compareTo()方法。
public class Person implements Comparable{
//此处省略JavaBean定义的基本步骤
@Override
public int compareTo(Object o){
if(o instanceof Person){
Person p = (Person)o;
return this.age - p.age;
}
throws new RuntimeException("对象不可比!");
}
}
由上面代码可以看出,在实现compareTo()方法的时候,首先需要判断一下比较的对象是不是Person类,如果不是就没有意义,就会抛出异常。但是,由于Object类没有抛出异常,所以它的子类Person类抛出的异常要比Object类范围小,所以不能声明throws异常。因此,受检异常就不能被抛出,只能抛出非受检异常RuntimeException。如果比较对象是Person类型,那么首先要造型,将Object引用转换成Person类型,然后返回本对象的属相值与被比较对象的属性值的差(这里用年龄做比较)。如果本对象的年龄比被比较对象的年龄大,那么返回值是正数;如果小返回负数;如果相等则返回0。最后TreeSet会按照返回的值来判断Person对象的大小。这样,就能将Person类型的对象存入TreeSet中了。
2. 创建一个比较器实现Comparator接口,在比较器中实现compare()方法。创建TreeSet时将比较器作为构造器的参数传入。
public class PersonComparator implements Comparator{
@Override
public int compare(Object o1, Object o2){
if(o1 instanceof Person && o2 instanceof Person){
return ((Person)o1).getAge() - ((Person)o2).getAge();
}
throw new RuntimeException("对象不可比!");
}
}
由上面代码可以看出,两种方案是大同小异的,都需要实现比较接口。它们的不同之处在于:
①实现接口的位置不同。
第一种方案是在原类上声明实现Comparable接口,并且在原类中实现compareTo()方法。这个方法时属于这个类中的成员的。而第二种方案是自己写一个类做为比较器,这个比较器声明实现Comparator接口并实现compare()方法,原类是不需要进行任何改变的。
②compareTo()方法只有一个参数,那就是被比较对象,而调用者是比较对象。compara()方法有两个参数,分别是需要比较的两个对象。
③在使用第一种方案时创建HashSet对象时构造器不需要传入任何参数,因为比较已经作为Person类本身的特性了。而使用第二种方案创建HashSet对象时需要将比较器当做参数传入HashSet的构造器中,因为这时Person类并没有比较的特性。
Set set = new HashSet(new PersonComparator());
by Karl