1. TreeSet介绍
TreeSet继承SortedSet接口,所以它也是一个有序的集合,TreeSet是基于TreeMap实现的,在new TreeSet集合时,底层是new了一个TreeMap集合,往TreeSet集合中放数据实际是放到了TreeMap中。
2. TreeSet数据结构
public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, java.io.Serializable
TreeSet继承于AbstractSet,是一个有序的,无重复的集合。
3. TreeSet源码
private transient NavigableMap<E,Object> m; //PRESENT是value的固定值 private static final Object PRESENT = new Object(); //无参构造方法,创建一个空的TreeMap public TreeSet() { this(new TreeMap<>()); } //带有比较器的构造方法 public TreeSet(Comparator<? super E> comparator) { this(new TreeMap<>(comparator)); } //带有指定集合的构造方法 public TreeSet(Collection<? extends E> c) { this(); addAll(c); } //指定SortSet集合的构造方法 public TreeSet(SortedSet<E> s) { this(s.comparator()); addAll(s); } //调用TreeMap集合的迭代器 public Iterator<E> iterator() { return m.navigableKeySet().iterator(); } public int size() { return m.size(); } public boolean isEmpty() { return m.isEmpty(); } public boolean contains(Object o) { return m.containsKey(o); } public boolean add(E e) { return m.put(e, PRESENT)==null; } public boolean remove(Object o) { return m.remove(o)==PRESENT; } public void clear() { m.clear(); }
4. TreeSet实例
public class TreeSetTest01 { public static void main(String[] args) { Set<String> str = new TreeSet<>(); str.add("A"); str.add("D"); str.add("E"); str.add("G"); str.add("H"); str.add("A"); //set中不允许添加重复元素,所以只会保存一个"A" for(String s : str){ System.out.println(s); } TreeMap<Integer,String> treeMap = new TreeMap<>(); treeMap.put(4,"AA"); treeMap.put(2,"bb"); treeMap.put(3,"ee"); treeMap.put(3,"ff"); treeMap.put(1,"gg"); Set<Integer> s = treeMap.keySet(); for(Integer i : s){ System.out.println(i + "=" + treeMap.get(i)); } } }
5. TreeSet中添加自定义类型
public class TreeSetTest02 { public static void main(String[] args) { NewPerson np1 = new NewPerson(10); NewPerson np2 = new NewPerson(20); NewPerson np3 = new NewPerson(5); NewPerson np4 = new NewPerson(50); TreeSet ts = new TreeSet(); ts.add(np1); ts.add(np2); //ClassCastException,NewPerson类型没有实现Comparable接口 ts.add(np3); ts.add(np4); } } class NewPerson{ private int age; public NewPerson(int age){ this.age = age; } @Override public String toString() { return "Person[age =" + age +"]"; } }
TreeSet中不能直接添加自定义类型数据,添加自定义类型数据有两种方法
(1)实现Comparable接口,重写compareTo方法;
(2)实现Comparator接口;
第一种:实现Comparable接口,重写compareTo方法
public class TreeSetTest01 { public static void main(String[] args) { TreeSet<Animal> ts = new TreeSet<>(); ts.add(new Animal(3,"dog")); ts.add(new Animal(2,"cat")); ts.add(new Animal(2,"dog")); ts.add(new Animal(1,"bird")); for(Animal an : ts){ System.out.println(an); } } } class Animal implements Comparable<Animal>{ private int age; private String name; public Animal(int age, String name){ this.age = age; this.name = name; } @Override public String toString() { return name + "=" + age; } @Override public int compareTo(Animal o) { if(this.age == o.age){ return this.name.compareTo(o.name); //如果年龄相等,比较name,字符串已经是实现了comparaTo方法,可以直接调用 } return this.age - o.age; } }
第二种:在初始化TreeSet时,传入比较器(比较器是实现了Compartor接口的对象)作为构造函数参数
public class TreeSetTest02 { public static void main(String[] args) { Cat c1 = new Cat(6,"black"); Cat c2 = new Cat(2,"white"); Cat c3 = new Cat(3,"color"); TreeSet<Cat> ts = new TreeSet<>(new Comparator<Cat>() { //传入比较器,使用匿名内部类,直接new 接口 @Override public int compare(Cat o1, Cat o2) { return o1.age - o2.age; } }); //TreeSet<Cat> ts = new TreeSet<>(new CatCom()); ts.add(c1); ts.add(c2); ts.add(c3); for(Cat c : ts){ System.out.println(c); } } } class Cat{ public int age; public String color; public Cat(int age,String color) { this.age = age; this.color = color; } @Override public String toString() { return age + "=" + color; } } /*class CatCom implements Comparator<Cat>{ @Override public int compare(Cat o1, Cat o2) { return o1.age - o2.age; } }*/
使用匿名内部类直接new 接口,其实也是相当于重新写了一个类CatCom,实现了Compartor接口,在初始化TreeSet时传入实现Comparator接口的类作为参数
两种实现方式比较:
需要频繁变化比较规则时推荐使用Comparator,符合OCP原则;比较规则固定时推荐使用Comparable,比如String和Integer;