A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 王海飞 黑马帝   /  2011-7-21 21:31  /  2348 人查看  /  6 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?

6 个回复

倒序浏览

关于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"表示对象的值是否相同.

评分

参与人数 1技术分 +1 收起 理由
admin + 1 新手报到

查看全部评分

回复 使用道具 举报
黑马网友  发表于 2011-7-21 22:01:13
藤椅
==比较的是对象,equal比较的是值

评分

参与人数 1技术分 +1 收起 理由
admin + 1 新手报到

查看全部评分

回复 使用道具 举报
黑马网友  发表于 2011-7-21 22:55:14
板凳
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]

评分

参与人数 1技术分 +2 收起 理由
admin + 2 非常认真!

查看全部评分

回复 使用道具 举报
黑马网友  发表于 2011-7-21 22:55:20
报纸

回复 楼主 的帖子

“equals”和“=”的区别就是:“equals”比较的是堆内存里面的东西,“==”比较的是堆内存的首地址。

堆内存是由new这样的关键字产生的,包括数组以及对象等,堆内存由垃圾回收器管理,当为一个数组或一个对象new出一段堆内存之后,这段堆内存的首地址(引用变量)便会存放于栈内存中。
回复 使用道具 举报
黑马网友  发表于 2011-7-21 22:57:15
地板
实际上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]

评分

参与人数 1技术分 +2 收起 理由
admin + 2 加分必须的

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马