黑马程序员技术交流社区

标题: 关于 Set [打印本页]

作者: 王海飞    时间: 2011-7-21 21:31
标题: 关于 Set
Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?
作者: 孙斌    时间: 2011-7-21 21:45
标题: 关于Set
Set
A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element. As implied by its name, this interface models the mathematical set abstraction.
根据JDK文档中的说明应该用equals,"=="表示对象(对象的地址)是否相同,"equal"表示对象的值是否相同.
作者: 匿名    时间: 2011-7-21 22:01
==比较的是对象,equal比较的是值
作者: 匿名    时间: 2011-7-21 22:55
Set有两个子类:
|-  HashSet
    |- 请参看[url=http://bbs.itheima.com/thread-170-1-1.html]HashSet详述[/url]
|-  TreeSet
    |-  TreeSet中保存的每个元素,都必须实现了Comparable接口。 而消除重复的元素,是通过接口中的CompareTo方法来完成的。

public int compareTo(T o)
|-  如果compareTo()方法返回0 则意味着正在比较的2个对象相等。
|-  而两个对象相等在Set中是不允许出现的。
|-  因此 重写compareTo()方法时 要将对象的所有字段都进行比较。
|-  要保证只有在两个对象的各个属性的值都相同的情况下,咱们才返回0。否则就返回1或-1。
|-  返回一个大于0的数  意味着 需要将当前对象和参数对象交换位置。
|-  返回一个小于0的数  意味着 不需要将当前对象和参数对象交换位置。

看看Person类:[code=java]package org.cxy.demo;

public class Person implements Comparable<Person>{
        private String name;
        private int age;
       
        public Person(String name, int age) {
                this.name = name;
                this.age = age;
        }

        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 int compareTo(Person arg0) {
                int result = this.name.compareTo(arg0.getName());
                // 若姓名相同,则按照年龄从大到小排序。
                if( result == 0){
                        result = arg0.getAge() - this.age ;
                }
                return result;
        }
        public String toString(){
                return "姓名:"+this.name+",年龄:"+this.age;
        }
}[/code]测试类代码:[code=java]package org.cxy.demo;

import java.util.*;
public class Demo {
        public static void main(String[] args){
                TreeSet<Person> set = new TreeSet<Person>();
                set.add(new Person("No-5",20));
                set.add(new Person("No-5",25));
                set.add(new Person("No-1",30));
                System.out.println(set);
        }
}[/code]当姓名相同时,按照年龄从大到小排序。 否则就按照姓名从小到大排序。
程序运行结果:[code=java][姓名:No-1,年龄:30, 姓名:No-5,年龄:25, 姓名:No-5,年龄:20][/code]
作者: 匿名    时间: 2011-7-21 22:55
标题: 回复 楼主 的帖子
“equals”和“=”的区别就是:“equals”比较的是堆内存里面的东西,“==”比较的是堆内存的首地址。

堆内存是由new这样的关键字产生的,包括数组以及对象等,堆内存由垃圾回收器管理,当为一个数组或一个对象new出一段堆内存之后,这段堆内存的首地址(引用变量)便会存放于栈内存中。
作者: 匿名    时间: 2011-7-21 22:57
实际上Set就是Collection,只是Set不允许包含重复元素

Set通过equals方法判断两个对象是否相同,而不是==,所以只要equals返回true,那么两个对象就是相同的,无论实际上这两个对象差别有多大,而只要equals返回false,即使两个对象实际上是同一个对象,Set也会当成两个对象处理。

HashSet类
HashSet具有的特点:
1 不能保证元素的排列顺序,顺序可能发生变化。
2 HashSet不是同步的,如果多个线程同时访问一个Set集合,如果多个线程同时访问一个HashSet,如果有2条或者以上的线程修改了  HashSet集合时,必须通过代码来保证其是同步的(TreeSet和EnumSet也一样)。
3 集合元素可以是null。

HashSet判断两个元素相等是的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode方法返回的值也相等。
如果equals比较相等,hashCode返回值不同,则HashSet将会把两个对象保存到不同的位置,即都添加成功
如果equals不相等,hashCode返回值相等,则HashSet将会试图把两个对象保存到同一个位置,实际上又不行,处理起来将很复杂,将导致性能下降。

所以,重写某个类的equals方法和hashCode方法时,应该尽量保证对象通过equals返回true是,它们的hashCode返回值也相等。

重写hashCode的基本规则
1 过equals返回true是,它们的hashCode返回值也相等
2 对象中用作equals比较标准的属性,都应该用来计算hashCode值。

当向HashSet中添加可变对象是,必须非常的小心,如果修改HashSet中的对象时,有可能导致该对象与集合中的其他对象相等,从而导致HashSet无法准确访问该对象。

HashSet的子对象LinkedHashSet使用链表维护元素次序,使元素以插入顺序保存,性能略低于HashSet。[code=java]package cn.itcast.zhanjc;


import java.util.*;
/**
*
*/

//类A的equals方法总是返回true,但没有重写其hashCode()方法
class A
{
        public boolean equals(Object obj)
        {
                return true;
        }
}
//类B的hashCode()方法总是返回1,但没有重写其equals()方法
class B
{
        public int hashCode()
        {
                return 1;
        }
}
//类C的hashCode()方法总是返回2,但没有重写其equals()方法
class C
{
        public int hashCode()
        {
                return 2;
        }
        public boolean equals(Object obj)
        {
                return true;
        }
}
public class HashCode
{
        public static void main(String[] args)
        {
                HashSet books = new HashSet();
                //分别向books集合中添加2个A对象,2个B对象,2个C对象
                books.add(new A());
                books.add(new A());
                books.add(new B());
                books.add(new B());
                books.add(new C());
                books.add(new C());
                System.out.println(books);
        }
}[/code]结果[code=java][cn.itcast.zhanjc.B@1, cn.itcast.zhanjc.B@1, cn.itcast.zhanjc.C@2, cn.itcast.zhanjc.A@1fb8ee3, cn.itcast.zhanjc.A@c17164][/code]------------------------------------------------------------------------------------
从上可以看到当重写一个equals或者hashCode()时候集合能添加通过equals方法返回true的元素、并且虽然HashCode()方法返回true但是HashSet依然把他们当成两个对象、这样就与Set集合规则不符合
所以在重写HashCode()方法的基本原则上要注意:
1、当两个对象通过equals方法返回true时,这两个对象的HashCode()也应该相等
2、对象中用作equals比较标准的属性都应该用来计算HashCode的值

您也可查看这个帖子,其中希望能解决您的问题
[url]http://bbs.itheima.com/viewthread.jsp?tid=238&page=1#pid3742[/url]




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2