TreeSet实现详解
TreeSet是SortedSet接口的实现类,所以可以看出TreeSet是有序的。
与HashSet集合采用hash算法来决定元素的存储位置不同,TreeSet采用红黑树的数据结构来存储集合元素,那么TreeSet进行排序的规则是怎样的?TreeSet支持两种排序:自然排序和定制排序。
1、自然排序
TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间的大小关系,然后将集合元素按升序排列,这种方式就是自然排序。
如果试图将元素添加到TreeSet集合中,只有第一个元素无须实现Comparable接口,后面添加的元素都必须实现该接口,但是这样会引发ClassCastException。所以在将元素添加到集合之前,应该将该对象实现Comparable接口。当实现了该接口时,添加元素时,会自动调用compareTo(Object obj)方法,这就要求集合中的其他元素与该元素是同一个类的对象。
当一个对象调用该方法与另一个对象进行比较时,如:obj1.compareTo(obj2),如果该方法返回0,说明两者相等;如果返回时一个正数,说明obj1 > obj2;如果返回一个负数,表明 obj1< obj2;
简单例子1:
/*
通过姓名进行升排序
*/
package com.microtao.set;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
class Person implements Comparable {
private String name;
private int age;
private String sex;
public Person() {
}
public Person(String name, int age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]";
}
/*
* 重写compareTo方法进行比较
*/
@Override
public int compareTo(Object o) {
Person p = (Person) o;
if (this.name.compareTo(p.name) > 0) {
return 1;
}
if (this.name.compareTo(p.name) < 0) {
return -1;
}
return this.name.compareTo(p.name);
}
}
public class TreeSetTest {
public static void main(String[] args) {
Set ts = new TreeSet();
ts.add(new Person("as", 17, "男"));
ts.add(new Person("qeq", 32, "男"));
ts.add(new Person("21sd", 53, "男"));
ts.add(new Person("sc", 33, "男"));
ts.add(new Person("sa", 33, "男"));
Iterator it = ts.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
运行结果:
Person [name=21sd, age=53, sex=男]
Person [name=as, age=17, sex=男]
Person [name=qeq, age=32, sex=男]
Person [name=sa, age=33, sex=男]
Person [name=sc, age=33, sex=男]
简单例子2:
/*
通过年龄进行升排序
*/
package com.microtao.set;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
class Person implements Comparable {
private String name;
private int age;
private String sex;
public Person() {
}
public Person(String name, int age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]";
}
/*
* 重写compareTo方法按照年龄进行升排序
*/
@Override
public int compareTo(Object o) {
Person p = (Person) o;
if(this.age > p.age ) {
return 1;
}
if(this.age < p.age ) {
return -1;
}
return this.name.compareTo(p.name);
}
}
public class TreeSetTest {
public static void main(String[] args) {
Set ts = new TreeSet();
ts.add(new Person("as", 17, "男"));
ts.add(new Person("qeq", 32, "男"));
ts.add(new Person("21sd", 53, "男"));
ts.add(new Person("sc", 33, "男"));
ts.add(new Person("sa", 33, "男"));
Iterator it = ts.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
运行结果:
Person [name=as, age=17, sex=男]
Person [name=qeq, age=32, sex=男]
Person [name=sa, age=33, sex=男]
Person [name=sc, age=33, sex=男]
Person [name=21sd, age=53, sex=男]
2、定制排序
当元素自身不具备比较性,或者自身具备的比较性不是所需要的,那么此时可以让容器自身具备。需要定义一个类实现Comparator,重写compare方法,并将该接口的实现类作为参数传递给TreeMap集合构造方法。
**注意:当Comparable比较方式和Comparator比较方式同时存在时,以Comparator的比较方式为主。**在重写compareTo或者compare方法时,必须要明确比较的主要条件相等时要比较的次要条件。
简单例子:
package com.microtao.set;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
class P{
private String name;
private int age;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public P(String name, int age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]";
}
}
/** 实现Comparator接口,并将两个对象进行比较
* 首先依据年龄进行排序,如果年龄相等的话,并不表示他是同一个人,其次会对姓名进行排序,如果姓名也是一样的话
* 表明这两个对象是同一个对象,只有一个该对象被加入到集合中。
* @author Microtao
*
*/
class MyComparator implements Comparator{
@Override
public int compare(Object o1, Object o2) {
Person p1 = (Person) o1;
Person p2 = (Person) o2;
if(p1.getAge() > p2.getAge()) {
return 1;
}
if(p1.getAge() < p2.getAge()) {
return -1;
}
return p1.getName().compareTo(p2.getName());
}
}
public class TreeSetTest2 {
public static void main(String[] args) {
TreeSet ts = new TreeSet(new MyComparator());
ts.add(new Person("ada",52,"男"));
ts.add(new Person("dwdd",12,"男"));
ts.add(new Person("fds",32,"男"));
ts.add(new Person("gs",5,"男"));
ts.add(new Person("gc",5,"男"));
Iterator it = ts.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
运行结果:
Person [name=gc, age=5, sex=男]
Person [name=gs, age=5, sex=男]
Person [name=dwdd, age=12, sex=男]
Person [name=fds, age=32, sex=男]
Person [name=ada, age=52, sex=男]
总结:
- TreeSet是一个有序的集合,基于TreeMap实现,支持两种排序方式:自然排序和定制排序。主要是实现Comparable接口重写comparaTo()方法,与实现Comparator接口,重写compare(Obj o1,Obj o2),并将其实现类作为参数传递给TreeSet。
- TreeSet是非同步的,线程不安全。