在TreeSet集合的时候我不太清楚equals和实现Comparable接口中compareTo方法判断元素会不会出现矛盾的情况。
我在网上看过这个问题他们的说法是http://blog.csdn.net/bluishglc/article/details/20212599这个地址的说法是:这是一个非常基础的问题,但是实际编程中还是比较容易被忽视而导致一些看似奇怪的bug,本文对该问题进行一个小结。
我们知道,Set集合的维护的元素是唯一的,不会出现两个一样的元素,这是通过元素的equals和hashCode方法来判定的。而对于TreeSet来说,它本身除了是一个Set集合,同时还会依据一个Comparator或是Comparable接口对元素进行排序。我们就以Comparable的compareTo方法为例,当这个方法返回0是表示的也是“两个元素相等”,那么这就有可能与equals方法产生冲突,那么TreeSet是如何处理compareTo和equals方法两者之间的关系呢?
先不管两者发生冲突时的处理方法,作为良好的编程实践,我们应该首先保证equals,hashCode和compareTo三者的行为是一致的,这样才不会出现怪异的问题。接下来我们看一下当equals和compareTo行为不一致时TreeSet是如何处理的。从TreeSet文档上我们可以找到以下一段描述:
假定使用 Comparator c 将满足 (a.equals(b) && c.compare(a, b) != 0) 的两个元素 a 和 b 添加到一个空 TreeSet 中,则第二个 add 操作将返回 true(树 set 的大小将会增加),因为从树 set 的角度来看,a 和 b 是不相等的,即使这与 Set.add 方法的规范相反。
在Comparable的文档上我们可以找到另一种描述:
如果将两个键 a 和 b 添加到没有使用显式比较器的有序集合中,使 (!a.equals(b) && a.compareTo(b) == 0),那么第二个 add 操作将返回 false(有序集合的大小没有增加),因为从有序集合的角度来看,a 和 b 是相等的。
很明确,两段说明从一正一反两个方向描述了一个一致的原则:是否能加入一个有序集合是由equals方法决定的,但是equals为true,compare不为0的元素加入到集合中后,在排序上会显得怪异。
下面看我的程序:- class TreeSetDemo
- {
- public static void main(String[] args)
- {
- TreeSet ts = new TreeSet();
- /*
- ts.add("cba");
- ts.add("aaa");
- ts.add("bca");
- ts.add("Dbcd");
-
- Iterator it = ts.iterator();
-
- while(it.hsNext())
- {
- System.out.println(it.next());
- }
- */
- ts.add(new Student("lisi02",22));
- ts.add(new Student("lisi02",22));
- ts.add(new Student("lisi09",19));
- ts.add(new Student("lisi01",40));
- ts.add(new Student("lisi09",19));
- Iterator it = ts.iterator();
- while(it.hasNext())
- {
- Student stu = (Student)it.next();
- System.out.println(stu.getName()+"...."+stu.getAge());
- }
- }
- }
- class Student implements Comparable//该接口强制让学生具备比较性。
- {
- private String name;
- private int age;
- Student(String name,int age)
- {
- this.name = name;
- this.age = age;
- }
- @Override
- public int hashCode() {
- System.out.println("In hashCode.....");
- return age;
- }
- @Override
- public boolean equals(Object obj){
- System.out.println("in here..........");
- if(!(obj instanceof Student))
- throw new RuntimeException("不是学生对象");
- Student s = (Student)obj;
- System.out.println("in here..........");
- return this == s;
- }
- public int compareTo(Object obj)
- {
- //return 1;//(03)怎么存就怎么取。
-
- if(!(obj instanceof Student))
- throw new RuntimeException("不是学生对象");
- Student s = (Student)obj;
- System.out.println(this.name+"....compareto...."+s.name);
- if(this.age>s.age)
- return 1;
- if(this.age==s.age)
- {
- return this.name.compareTo(s.name);
- }
- return -1;
-
- }
- public String getName()
- {
- return name;
- }
- public int getAge()
- {
- return age;
- }
- }
复制代码
运行结果:
可以看到,TreeSet集合根本没有调用hashCode方法和equals方法,只是 通过实现Comparable的compareTo方法比较的,而且我认为TreeSet底层用的二叉树的存储方式,也不需要hashCode算法来进行存储,hashCode方法是为了给数据分配哈希域。
大家怎么看??
|
|