`
L.G.Alexander
  • 浏览: 157993 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

(十六):Set元素不能重复,重写equals方法就必须重写hashCode方法

阅读更多
public class People{
	String name;
	public People(String name){
		this.name = name;
	}
	public String getName(){
		return name;
	}
}
public class SetTest {
	public static void main(String[] args){
		Set<String> set = new HashSet<String>();//语句(1)
		System.out.println(set.add("abc"));//语句(2)
		System.out.println(set.add("xyz"));//语句(3)
		System.out.println(set.add("abc"));//语句(4)
		for(Iterator<String> it = set.iterator();it.hasNext();){//语句(5)
			System.out.println(it.next());
		}
		
		Set<People> st = new HashSet<People>();//语句(6)
		st.add(new People("zhangsan"));//语句(7)
		st.add(new People("lisi"));//语句(8)
		st.add(new People("zhangsan"));//语句(9)
		for(Iterator<People> it = st.iterator();it.hasNext();){//语句(10)
			System.out.println(it.next().getName());
		}
	}
}

问题1:执行完语句语句(1)(2)(3)(4)(5),打印结果是什么?为什么?
解答:执行完语句语句(1)(2)(3)(4)(5),打印结果是true,true,false,abc,xyz。因为String类重写Object类的equals和hashCode方法。
分析:Set是数学上的集合的集合的概念。关于数学上的集合它是不允许有重复元素的,举例:我有一个集合,元素是1、2、3、4、5,我在往集合里面增加元素3,这个集合的元素还是1、2、3、4、5,不会说是1、2、3、3、4、5。集合里的元素不允许有重复元素。java里面的Set完全反映到数学集合上的意义。java里面的Set里面的元素也是不运行重复的。在上述代码中有两个abc,是重复的。既然是重复的,你添加完一个再去添加另外一个相同的元素,是不能添加进去的。关于Set里面的一些方法,jdk文档是这样定义的:
boolean add(E e)
Adds the specified element to this set if it is not already present (optional operation). More formally, adds the specified element e to this set if the set contains no element e2 such that (e==null ? e2==null : e.equals(e2)). If this set already contains the element, the call leaves the set unchanged and returns false. In combination with the restriction on constructors, this ensures that sets never contain duplicate elements. (翻译:果 set 中尚未存在指定的元素,则添加此元素(可选操作)。更正式地说,如果此 set 没有包含满足下列条件的元素 e,则向 set 中添加指定的元素 o:(o==null ? e==null.equals(e))。如果此 set 已经包含指定的元素,则该调用不改变此 set 并返回 false。结合构造方法上的限制,这就可以确保 set 永远不包含重复的元素。)
The stipulation above does not imply that sets must accept all elements; sets may refuse to add any particular element, including null, and throw an exception, as described in the specification for Collection.add. Individual set implementations should clearly document any restrictions on the elements that they may contain.(翻译:上述规定并未暗示 set 必须接受所有元素;set 可以拒绝添加任意特定的元素,包括 null,并抛出异常,这与 Collection.add 规范中所描述的一样。每个 set 实现应该明确地记录对其可能包含元素的所有限制。)
也就是说,添加一个元素成功,会返回true,否则返回false.

问题2:执行完语句语句(6)(7)(8)(9)(10),打印结果是什么?为什么?
解答:执行完语句语句(6)(7)(8)(9)(10),打印结果是zhangsan,lisi,zhangsan。
分析:People类没有重写Object类的equals和hashCode方法,而Object类的equals方法比较的是对象的内存地址,Object类的hashCode方法返回的也是对象的内存地址,在语句(7)和语句(9)分别在堆里面生成了2个对象,它们的内存地址是不一样的。

问题3:为什么语句(4)中的abc添加不到Set中,而语句(9)中的第二个zhangsan能添加到Set中呢?
解答:学过数据结构就知道Hash是一个人的名字,在数据结构里面有Hash表Hash函数。在java里面对HashSet的实现也是使用Hash的方式去实现的。为什么用Hash的方式去实现呢?可以这样考虑:当如果不用Hash方式实现,还用正常方式实现,集合是不运行元素重复出现的,如果集合里已经有了1000个对象,这是我往集合里面增加第1001个对象,增加之前会把第1001个对象和集合里已经有的1000个对象一一比较,判断是否存在将要增加的对象,如果存在就不增加,如果不存在就增加,这样就存在效率问题。有十万个就要比较十万次,这么低的效率在我们现实开发里面是不允许的。java考虑到效率的问题没有按照正常的方式,而是采用了Hash的方式。HashSet的存储机制:Hash是散列,它是这样比较的,当往集合里面增加一个对象的时候,我们是把对象的引用(对象的内存地址)增加到集合里面去了,当把对象的引用增加到集合里面去后,集合要做什么呢?它首先读取增加对象的hashCode (调用对象的hashCode()方法,hashCode()方法在在Object类里面定义的),根据hashCode,集合去计算存放对象的位置,
当这个位置没有存放对象的话,集合就认为这个对象没有重复,直接就存放这个对象,这是第一种情况。第二种情况,首先它还是要计算hashCode,得到hash码,同样还是要计算位置,当它计算出位置时,发现这个位置已经有这个对象存在了,它并不会立刻告知增加不成功,它会接着调用你增加这个对象的equals方法跟已经在位置上存在的对象进行比较,如果equals方法返回true,表示这两个对象的内容是一样的,既然对象的内容是一样,集合就认为这个对象已经在集合里面存在了,就增加不进去了。集合的add方法返回一个false。如果equals方法返回false,表示将要增加的对象和集合里面已经存在的对象的内容不一样,既然内容不一样,集合就再去散列一次,计算出新的地址,把你这个对象放到新的地址上去,还是会增加成功。

问题4:怎样重写People类的equals和hashCode方法,而使语句(9)中的第二个zhangsan不能添加到Set中呢?
解答:代码如下:
@Override
	public boolean equals(Object obj) {
		if(obj == null) return false;
		if(this == obj) return true;
		if(obj instanceof People)
			if(obj.equals(this))return true;
		return false;
	}
	@Override
	public int hashCode() {
		return name.hashCode();
	}
总结:1、当向集合Set中增加对象时,首先集合计算要增加对象的hashCode码,根据该值来得到一个位置用来存放当前对象,挡在该位置没有一个对象存在的话,那么集合Set认为该对象在集合中不存在,直接增加进去。如果在该位置有一个对象存在的话,接着将准备增加到集合中的对象与该位置上的对象进行equals方法比较,如果该equals方法返回false,那么集合认为集合中不存在该对象,在进行一次散列,将该对象放到散列后计算出的新地址里,如果equals方法返回true,那么集合认为集合中已经存在该对象了,不会再将该对象增加到集合中了。
    2、重写equals方法的时候必须重写hashCode方法。如果一个类的两个对象,使用equals方法比较时,结果为true,那么该两个对象具有相同的hashCode。原因是equals方法为true,表明是同一个对象,它们的hashCode当然相同。
    3、Ojbect类的hashCode方法返回的是Object对象的内存地址。我们可以通过Integer.toHexString(new Object().hashCode);来得到。
   
分享到:
评论

相关推荐

    java中重写equals()方法的同时要重写hashcode()方法(详解)

    Java 中重写 equals() 方法的同时要重写 hashCode() 方法的重要性 在 Java 中,equals() 方法和 hashCode() 方法是两个紧密相关的方法,它们都是用于比较和标识对象的方法。equals() 方法用于比较两个对象的值是否...

    C# Equals 和 GetHashCode 方法重写

    ### C# Equals 和 GetHashCode 方法重写 在C#编程中,`Equals` 和 `GetHashCode` 方法是非常重要的成员方法,它们对于确保对象的正确比较以及高效地存储和检索对象至关重要。这两个方法通常需要在自定义类中进行...

    hashcode和equals的分析

    ### hashCode和equals方法详解 #### 一、hashCode方法解析 在深入探讨`hashCode`方法之前,我们需要了解Java集合框架的基本概念。Java集合框架主要包括两大类集合:`List`和`Set`。 - **List**:这是一个有序集合...

    探索Java中的equals()和hashCode()方法_动力节点Java学院整理

    例如,在Set中,使用hashCode方法来判断元素是否已经存在,如果元素已经存在,那么就不再添加,这样可以避免重复元素的存在。在List中,使用hashCode方法来判断元素是否已经存在,然后使用equals方法来比较元素的值...

    java中hashCode、equals的使用方法教程

    在Java编程语言中,`hashCode()` 和 `equals()` 方法对于对象的比较和处理至关重要,尤其在集合类(如Set和Map)中。这两个方法都源自`java.lang.Object`类,因此所有的Java类都默认继承了它们。理解并正确地重写这...

    java中hashCode方法与equals方法的用法总结

    当你创建一个新的类并打算将其实例存储在集合(如 `Set`)中时,应该同时重写 `equals()` 和 `hashCode()`。这是因为如果不这样做,可能会导致以下问题: 1. **重复元素**:即使两个对象通过 `equals()` 比较是相等...

    HashCode的用法详解

    如果我们不定义 equals() 方法,那么同一个类产生的两个内容完全相同的对象都可以存入 Set,这样就使得 HashSet 失去了它的意义。 hashCode() 的重写 为什么需要重写 hashCode()?因为我们需要确保对象的唯一性。...

    JAVA集合的使用(List、Map、Set、Queue,Collections、Comparable与Comparator,排序、搜索,内部类、equals、hashCode)

    要注意的是List,Set,Queue继承了Collection接口,...这里想用一个简单的例子展示一下他们的使用,内容包括:List、Map、Set、Queue,Collections、Comparable与Comparator,排序、搜索,内部类,泛型、重写equals、hashCode

    hashCode的作用

    如果两个对象的`hashCode`相同,则会进一步调用`equals`方法来判断这两个对象是否相等,避免重复插入相同的元素。 #### 4. `hashCode`与`equals`的关系 通常情况下,如果两个对象相等(即`equals`方法返回`true`)...

    java集合——Java中的equals和hashCode方法详解

    1. 如果两个对象通过`equals()` 方法比较相等,那么它们的`hashCode()` 方法必须返回相同的值。 2. 如果两个对象通过`equals()` 方法比较不相等,`hashCode()` 方法可能返回相同或不同的值。但是,为了优化哈希表的...

    java中set接口使用方法详解

    在Java编程中,Set接口是集合框架的一部分,它继承自Collection接口,主要用于存储不包含重复元素的集合。Set接口的实现类主要有HashSet、TreeSet和LinkedHashSet,它们各自有不同的特性和使用场景。 1. **HashSet*...

    java中List对象列表实现去重或取出及排序的方法

    Java中List对象列表实现去重或取出及排序的方法 ...去重和排序List对象列表可以使用多种方法,包括重写equals和hashCode方法,使用HashSet,使用Java 8的Stream API等。根据实际情况选择合适的方法来实现。

    CustomSet.zip

    9. ** equals() 和 hashCode()**:为了与其他集合比较,CustomSet需要重写equals()和hashCode()方法,确保集合间的相等性和哈希码的一致性。 自定义实现HashSet时,开发者需要特别关注性能和内存使用,确保在满足...

    java基础复习(秋招、提前批)

    - Set不允许元素重复,而List允许重复元素。 - List可以通过索引访问元素,而Set没有索引概念。 ArrayList和LinkedList的区别主要在于底层实现和性能: - ArrayList基于动态数组,适合于随机访问和增删元素在中间...

    hashCode方法的使用讲解

    如果有元素,再通过`equals`方法来判断新旧元素是否相等,如果相等,则不添加新元素,如果不等,就需要寻找下一个空的哈希桶,这就是所谓的哈希碰撞处理。 根据Java的规定,如果两个对象相等(即`equals`方法返回`...

    收集的电子书

    - 当重写equals方法时,必须同时重写hashCode方法。 - 保证对象相等时hashCode返回相同值,对象不等时hashCode返回不同值或相同值,但应注意后者可能影响性能。 7. Map接口的keySet()和values()方法: - keySet...

    set,list,map区别与联系.docx

    存入的元素必须重写equals()和hashCode()方法以保证元素唯一性。 - **TreeSet**:有序的Set,底层是红黑树结构,提供了排序功能。 - **LinkedHashSet**:兼具HashSet的查找速度和链表维护的插入顺序,遍历时按元素...

    set容器无重复注意问题.png

    凡是以hashcode为存储位置计算的容器都需要重写hashcoe方法,为什么重写类的hashcode和equals方法?如果不重写会有后果?以及set容器的元素储存方式

    java-专业】最全-JAVA面试题

    12. **Set的元素检查**:Set的元素不重复,使用iterator()遍历判断是否重复,equals()用于比较两个对象是否相等,而==则比较两个引用是否指向同一个对象。 13. **运行时异常**:常见的运行时异常包括Arithmetic...

    hhtc大一期末测试题Java分析题

    总结一下,Java中的Set接口确保了元素的唯一性,通过重写equals()和hashCode()方法,我们可以自定义元素的比较规则,例如在本例中基于学号判断学生对象的重复。此外,题目还涉及到了异常处理,创建自定义的编译异常...

Global site tag (gtag.js) - Google Analytics