TreeSet集合的自然排序与比较器排序、Comparable接口的compareTo()方法
【自然排序】
1 package com.hxl; 2 3 public class Student implements Comparable<Student> { 4 5 private String name; 6 private int age; 7 8 public Student() { 9 super(); 10 } 11 12 public Student(String name, int age) { 13 super(); 14 this.name = name; 15 this.age = age; 16 } 17 18 public String getName() { 19 return name; 20 } 21 22 public void setName(String name) { 23 this.name = name; 24 } 25 26 public int getAge() { 27 return age; 28 } 29 30 public void setAge(int age) { 31 this.age = age; 32 } 33 34 @Override 35 public int compareTo(Student s) { 36 // 先让两个对象的age属性做差比较,这个是主要排序条件 37 int num = this.age - s.age; 38 // 若age属性相同,再比较name属性(String类本身实现了Comparable接口) 39 // 即在主要排序条件相同的情况下,次要排序条件起作用 40 int flag = num == 0 ? this.name.compareTo(s.name) : num; 41 // 返回比较结果 42 return flag; 43 } 44 }
1 package com.hxl; 2 3 import java.util.TreeSet; 4 5 public class Test { 6 public static void main(String[] args) { 7 //这里使用的无参构造实例化TreeSet集合,则默认启用的是自然排序 8 TreeSet<Student> ts = new TreeSet<Student>(); 9 ts.add(new Student("cc", 11)); 10 ts.add(new Student("ee", 11)); 11 ts.add(new Student("cc", 22)); 12 ts.add(new Student("aa", 22)); 13 ts.add(new Student("bb", 11)); 14 15 for (Student s : ts) { 16 System.out.println(s.getName()+"_"+s.getAge()); 17 } 18 19 /* 20 为什么TreeSet集合中的元素既唯一又有序呢? 21 原因是它在存储元素的时候就是有序存储的(红黑树结构存储) 22 TreeSet的add()方法底层依赖的是Comparable的compareTo方法 23 这里就是说元素类本身要有自己的compareTo方法 24 所以元素类本身必须实现Comparable接口,重写compareTo方法 25 compareTo方法有个特点:它返回的是int型数据,结果有三类负数、0、正数 26 例如:(Java中一些常见的有比较意义的一些类都实现了Comparable接口,如Integer类) 27 Integer a = new Integer(10); 28 Integer b = new Integer(20); 29 int num = a.compareTo(b); //因为a小于b,所以num返回的是负数 30 而TreeSet的add()方法这样理解此返回值: 31 即返回负数则比根节点小,元素在此集合中唯一,元素存放根的左孩子 32 返回正数则比根节点大,元素在此集合中唯一,元素存放根的右孩子 33 返回0则表示,元素相同,在此集合中不唯一,故而丢掉不存放 34 由此可见,我们的重写的compareTo()方法决定了TreeSet集合中元素的去留和顺序! 35 */ 36 } 37 }
【比较器排序(外部类实现)】
1 package com.hxl; 2 3 public class Student{ 4 5 private String name; 6 private int age; 7 8 public Student() { 9 super(); 10 } 11 12 public Student(String name, int age) { 13 super(); 14 this.name = name; 15 this.age = age; 16 } 17 18 public String getName() { 19 return name; 20 } 21 22 public void setName(String name) { 23 this.name = name; 24 } 25 26 public int getAge() { 27 return age; 28 } 29 30 public void setAge(int age) { 31 this.age = age; 32 } 33 }
1 package com.hxl; 2 3 import java.util.Comparator; 4 5 public class MyComparator implements Comparator<Student> { 6 7 @Override 8 public int compare(Student s1, Student s2) { 9 // 先让两个对象的age属性做差比较,这个是主要排序条件 10 int num = s1.getAge() - s2.getAge(); 11 // 若age属性相同,再比较name属性(String类本身实现了Comparable接口) 12 // 即在主要排序条件相同的情况下,次要排序条件起作用 13 int flag = num == 0 ? s1.getName().compareTo(s2.getName()) : num; 14 // 返回比较结果 15 return flag; 16 } 17 }
1 package com.hxl; 2 3 import java.util.TreeSet; 4 5 public class Test { 6 public static void main(String[] args) { 7 //这里使用TreeSet(Comparator comparator)构造实例化TreeSet集合,则启用的是指定比较器排序 8 TreeSet<Student> ts = new TreeSet<Student>(new MyComparator()); 9 ts.add(new Student("cc", 11)); 10 ts.add(new Student("ee", 11)); 11 ts.add(new Student("cc", 22)); 12 ts.add(new Student("aa", 22)); 13 ts.add(new Student("bb", 11)); 14 15 for (Student s : ts) { 16 System.out.println(s.getName()+"_"+s.getAge()); 17 } 18 } 19 }
【比较器排序(内部类实现,如果只使用一次的话)】
1 package com.hxl; 2 3 public class Student{ 4 5 private String name; 6 private int age; 7 8 public Student() { 9 super(); 10 } 11 12 public Student(String name, int age) { 13 super(); 14 this.name = name; 15 this.age = age; 16 } 17 18 public String getName() { 19 return name; 20 } 21 22 public void setName(String name) { 23 this.name = name; 24 } 25 26 public int getAge() { 27 return age; 28 } 29 30 public void setAge(int age) { 31 this.age = age; 32 } 33 }
1 package com.hxl; 2 3 import java.util.Comparator; 4 import java.util.TreeSet; 5 6 public class Test { 7 public static void main(String[] args) { 8 //如果一个方法的参数是接口,那么真实想要的是其实是接口实现类的对象 9 //这里的对象只用一次,专门定义一个外部类显得麻烦 10 //匿名内部类可以实现这个需求 11 TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>(){ 12 public int compare(Student s1, Student s2) { 13 // 先让两个对象的age属性做差比较,这个是主要排序条件 14 int num = s1.getAge() - s2.getAge(); 15 // 若age属性相同,再比较name属性(String类本身实现了Comparable接口) 16 // 即在主要排序条件相同的情况下,次要排序条件起作用 17 int flag = num == 0 ? s1.getName().compareTo(s2.getName()) : num; 18 // 返回比较结果 19 return flag; 20 } 21 }); 22 ts.add(new Student("cc", 11)); 23 ts.add(new Student("ee", 11)); 24 ts.add(new Student("cc", 22)); 25 ts.add(new Student("aa", 22)); 26 ts.add(new Student("bb", 11)); 27 28 for (Student s : ts) { 29 System.out.println(s.getName()+"_"+s.getAge()); 30 } 31 } 32 }
【注】开发中会用最后一种,因为第一种只有固定的排序方式,第二种每次都要定义外面类显得麻烦。