自定义类的对象作为TreeSet元素的两种方法排序浅谈
2015-03-25 20:59
519 查看
我们知道TreeSet是Set接口下的一个实现类,TreeSet中的元素的排列顺序是和添加的顺序是没有关系的,并且它里面元素也是不能重复的
但是,TreeSet集合有它独有的特点,比如:
看输出结果:
![](http://img.blog.csdn.net/20150325205008048)
集合里元素的排序,虽然和你添加的顺序无关,但它会根据元素的unicode自然排序
但是,当你给集合中添加不同类型的数据时:
出现的结果是:
![](http://img.blog.csdn.net/20150325205348959)
就会报ClassCastException 类型转换异常
String 不能转成Integer类型,要排序,类型必须一致
说了这么多,TreeSet的排序好像就这么多了??
当然不是了,再往下看:
如果现在给集合里添加自定义类的对象怎么办?它又是怎么排序的呢?
再看运行结果:
![](http://img.blog.csdn.net/20150325211242541)
可以看出,给出的异常信息是:Person类不能比较,为什么呢?
它给的异常信息指示是应该去实现Comparable接口,一般系统内置的类都已经实现了Comparable接口,像上面的String类,Integer类
不卖关子了,说一下,自定义类的对象作为TreeSet元素的两种方法排序:
第一种:让自定义的类实现Comparable接口,并实现里面的compareTo()抽象方法,此时自定义的类的对象就有了可比性
第二种:当自定义的类没有实现Comparable接口时,这时自定义的类的对象也就不具备可比性了,这时需要让集合自身具备可比性,在集合初始化时,可以指明集合的比较方式,即在new TreeSet()时,在里面写一个匿名内部类,该匿名内部类实现Comparator接口,再重写它的compare()方法,具体看代码
先看第一种:
看下面的代码,排序规则是自定义的,先按照年龄排序,在年龄相同的情况下,再按名字排序
看输出结果:
![](http://img.blog.csdn.net/20150325212659554)
看中间两项,当年龄相同,都是20,此时,两者再按照名字排序
第二种:
此时,不实现Comparable接口,在new TreeSet()时,在里面写一个匿名内部类,该匿名内部类实现Comparator接口,再重写它的compare()方法
看输出结果:
![](http://img.blog.csdn.net/20150325225241853)
最后一行是最终结果,前面三行是比较过程
这里只按照年龄排序,没有再按名字排序,所以最后输出的set只有两项,第三项和第一项重复,直接被过滤掉
注意一点,当两种方法都存在时,到底以哪种方法为主呢?
答案是,以第二种方法,以比较器comparator()为主
我们可以验证一下:看下面,把两个方法都放进去
如果输出的集合中有三项,则说明以第一种为主;
如果输出的集合中有两项,则说明以第二种为主
最终结果为:
![](http://img.blog.csdn.net/20150325233727336)
输出的只有两项,说明了:当两种排序方式都存在时,以比较器为主
其实第一种方式是有安全隐患的,后续再来完善…..
但是,TreeSet集合有它独有的特点,比如:
import java.util.*; public class Test{ public static void main(String[] args){ TreeSet ts = new TreeSet(); ts.add("x"); ts.add("a"); ts.add("c"); ts.add("j"); System.out.println(ts); } }
看输出结果:
集合里元素的排序,虽然和你添加的顺序无关,但它会根据元素的unicode自然排序
但是,当你给集合中添加不同类型的数据时:
import java.util.*; public class Test{ public static void main(String[] args){ TreeSet ts = new TreeSet(); ts.add("x"); ts.add("a"); ts.add("c"); ts.add(1); System.out.println(ts); } }
出现的结果是:
就会报ClassCastException 类型转换异常
String 不能转成Integer类型,要排序,类型必须一致
说了这么多,TreeSet的排序好像就这么多了??
当然不是了,再往下看:
如果现在给集合里添加自定义类的对象怎么办?它又是怎么排序的呢?
import java.util.*; class Person{ private String name ; private int age; public Person(String name,int age){ this.name = name; this.age = age; } public String toString(){ return "Person[name="+name+",age="+age+"]"; } } public class Test{ public static void main(String[] args){ TreeSet ts = new TreeSet(); ts.add(new Person("ab",20)); ts.add(new Person("ac",10)); ts.add(new Person("aa",20)); ts.add(new Person("ad",50)); System.out.println(ts); } }
再看运行结果:
可以看出,给出的异常信息是:Person类不能比较,为什么呢?
它给的异常信息指示是应该去实现Comparable接口,一般系统内置的类都已经实现了Comparable接口,像上面的String类,Integer类
不卖关子了,说一下,自定义类的对象作为TreeSet元素的两种方法排序:
第一种:让自定义的类实现Comparable接口,并实现里面的compareTo()抽象方法,此时自定义的类的对象就有了可比性
第二种:当自定义的类没有实现Comparable接口时,这时自定义的类的对象也就不具备可比性了,这时需要让集合自身具备可比性,在集合初始化时,可以指明集合的比较方式,即在new TreeSet()时,在里面写一个匿名内部类,该匿名内部类实现Comparator接口,再重写它的compare()方法,具体看代码
先看第一种:
看下面的代码,排序规则是自定义的,先按照年龄排序,在年龄相同的情况下,再按名字排序
import java.util.*; class Person implements Comparable{ private String name ; private int age; public Person(String name,int age){ this.name = name; this.age = age; } public String toString(){ return "Person[name="+name+",age="+age+"]"; } // compareTo()方法是一个回调方法! // 返回值有3种情况: // 1. 返回大于0的数字,表示传入的参数比当前对象大 // 2. 返回小于0的数字,表示传入的参数比当前对象小 // 3. 返回0,表示当前对象等于传入的参数 public int compareTo(Object obj){ if(!(obj instanceof Person)){ //这里先判断Obj是不是Person的实例,如果不是直接抛异常 //不用再进行下面的比较 throw new ClassCastException("这不是人"); } Person p = (Person)obj; int n = this.age - p.age; //先按年龄比,年龄相同时,再按名字比 if(n == 0){ return this.name.compareTo(p.name); } return n; } } public class Test{ public static void main(String[] args){ Set set = new TreeSet(); set.add(new Person("ab",20)); set.add(new Person("ac",10)); set.add(new Person("aa",20)); set.add(new Person("ad",50)); System.out.println(set); } }
看输出结果:
看中间两项,当年龄相同,都是20,此时,两者再按照名字排序
第二种:
此时,不实现Comparable接口,在new TreeSet()时,在里面写一个匿名内部类,该匿名内部类实现Comparator接口,再重写它的compare()方法
import java.util.*; class Person{ private String name ; private int age; public Person(String name,int age){ this.name = name; this.age = age; } public String toString(){ return "Person[name="+name+",age="+age+"]"; } public int getAge(){ return age; } public String getName(){ return name; } } public class Test{ public static void main(String[] args){ Set set = new TreeSet(new Comparator(){ //这里的compare()传两个参数 //第一种方法里的compareTo()传一个参数 public int compare(Object obj1,Object obj2){ if(!((obj1 instanceof Person)&&(obj1 instanceof Person))){ throw new ClassCastException("这不是人"); } Person p1 = (Person)obj1; Person p2 = (Person)obj2; System.out.println(p1 + "vs" + p2); return p1.getAge()-p2.getAge(); } }); set.add(new Person("ab",20)); set.add(new Person("ac",10)); set.add(new Person("aa",20)); System.out.println(set); } }
看输出结果:
最后一行是最终结果,前面三行是比较过程
这里只按照年龄排序,没有再按名字排序,所以最后输出的set只有两项,第三项和第一项重复,直接被过滤掉
注意一点,当两种方法都存在时,到底以哪种方法为主呢?
答案是,以第二种方法,以比较器comparator()为主
我们可以验证一下:看下面,把两个方法都放进去
import java.util.*; class Person implements Comparable{ //这里实现了Comparable接口 private String name ; private int age; public Person(String name,int age){ this.name = name; this.age = age; } public String toString(){ return "Person[name="+name+",age="+age+"]"; } public int getAge(){ return age; } public String getName(){ return name; } public int compareTo(Object obj){ if(!(obj instanceof Person)){ throw new ClassCastException("这不是人"); } Person p = (Person)obj; int n = this.age - p.age; if(n == 0){ return this.name.compareTo(p.name); } return n; } } public class Test{ public static void main(String[] args){ Set set = new TreeSet(new Comparator(){ //这里也实现了Comparator接口 //那么以哪种为主呢? //看最下面的结果 public int compare(Object obj1,Object obj2){ if(!((obj1 instanceof Person)&&(obj1 instanceof Person))){ throw new ClassCastException("这不是人"); } Person p1 = (Person)obj1; Person p2 = (Person)obj2; return p1.getAge()-p2.getAge(); } }); set.add(new Person("ab",20)); set.add(new Person("ac",10)); set.add(new Person("aa",20)); System.out.println(set); } }
如果输出的集合中有三项,则说明以第一种为主;
如果输出的集合中有两项,则说明以第二种为主
最终结果为:
输出的只有两项,说明了:当两种排序方式都存在时,以比较器为主
其实第一种方式是有安全隐患的,后续再来完善…..
相关文章推荐
- 集合框架_TreeSet的add()方法源码再次解读和TreeSet对元素排序的总结
- 往TreeMap和TreeSet里添加自定义对象的两种比较方法
- 黑马程序员对TreeSet集合中的元素排序的两种方式
- TreeSet(有序集合)对Comparable元素的排序(或使用Comparator)与元素equals方法的关系
- 黑马程序员自学笔记————对于TreeSet实现排序的两种方法;
- TreeSet方法之一 当向TreeSet中添加Person对象 续 确定按哪个属性排序
- 将自定义对象作为元素存到TreeSet集合中
- java基础—自定义一个比较器,对TreeSet 集合中的元素按指定方法来排序(java集合六)
- 往TreeSet中存入自定义对象,并且使用自定义排序方法(实现comparetor)
- 浅谈TreeSet中的两种排序方式
- 黑马程序员训练营---------TreeSet集合中对象进行排序的两种方式
- 黑马程序员 TreeSet排序的两种实现方式
- java怎么判断两个Set 里的对象的值是否相同【两个set中的值是否相等】、java treeset和hashset如何判断元素是否相同【即对象是否完全相同;利用一个set去除重复元素】
- Java基础15:treeset;排序方法-比较器;泛型;
- 实现TreeSet排序和遍历map的方法
- 浅谈jQuery this和$(this)的区别及获取$(this)子元素对象的方法
- 编写一个排序函数,实现数字排序。排序方法由客户函数实现,函数参数个数为两个,两个参数的关系作为排序后的元素间的关系。
- Java按照对象属性排序的两种方法
- 【Java面试题】42 TreeSet里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的compareTo方法,还是使用的子类的compareTo方法,还是抛异常!
- Java实现对象排序的两种方法