`
My*Love
  • 浏览: 72477 次
  • 性别: Icon_minigender_1
  • 来自: 湖南
社区版块
存档分类
最新评论

理解Set里面为何不能有重复对象

    博客分类:
  • JAVA
阅读更多
   最近到处参加笔试,也没好好的去研究这些题目,但我发现好多笔试里面,String真的差不多必考,然后就是==与equals()的用法,基本屡试不爽。
   昨天不知怎么又搞到equals()去了,equals()方法是Object里面的一个方法,里面实现很简单:

 public boolean equals(Object obj) {
	         return (this == obj);
              }

其实里面比较的是两个对象的引用是否相同(即对象的地址值是否相同),但像String、Integer等这些引用数据的类型里已经重写了Object里面的equals()方法,如String中的equals()方法内容:
 public boolean equals(Object anObject) {
	if (this == anObject) {
	    return true;
	}
	if (anObject instanceof String) {
	    String anotherString = (String)anObject;
	    int n = count;
	    if (n == anotherString.count) {
		char v1[] = value;
		char v2[] = anotherString.value;
		int i = offset;
		int j = anotherString.offset;
		while (n-- != 0) {
		    if (v1[i++] != v2[j++])
			return false;
		}
		return true;
	    }
	}
	return false;
    }

第一个if比较引用是否相同,第二个if是比较字符串的值是否全相等,可以说这些重写后的equals()方法其实比较的是对象的内容是否相同。
     其实也可以想到Set怎么实现的了,它肯定是在你add一个对象的时候,调用了equals方法,看里面有没有相同对象。下面来看一个示例:
Student类

public class Student {
	private int age;
	private String name;

	public Student(int age, String name) {
		this.age = age;
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String toString() {
		return age + " " + name;
	}
}

测试一下:
  
   public static void main(String args[]) {
		
		Set<Student> set = new HashSet<Student>();
		set.add(new Student(1, "czc"));
		set.add(new Student(2, "yqq"));
		set.add(new Student(3, "lz"));
		set.add(new Student(1, "czc"));

		Iterator<Student> it = set.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}
   

输出结果为:
          2 yqq
         1 czc
         3 lz
         1 czc
为什么会有两个相同的对象?
      查看HashSet的add方法,你会发现它是把对象放到一个HashMap里面,HashMap里面的put方法实现如下:
 public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
           if (e.hash == hash && ((k = e.key) == key || key.equals(k))){
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }

if (e.hash == hash && ((k = e.key) == key || key.equals(k)))

从红色那一行可以看出,它判断是不是同一对象,还用到了一个hash值,即对象的hashCode值。
     hashCode()方法是Object里面的一个本地(native,实现看不到,应该是C/C++去实现的,具体也不懂)方法,像String、Integer等类都重写了hashCode方法,不同类的实现都用到了不同算法,感觉还是Integer最简单,直接就是输入的那个数。
     现在应该知道为什么输出两个相同的对象了吧,因为Student是自己写的一个类,用的是Object里面的equals()方法,知道Object里面方法的实现吧,其实就是比较引用是否相同,显然new出来的是两个不同的东西,所以Set认为是两上不同对象,都放进去了。
    可能有人会发现,为什么定义两个相同字符串对象,放到Set里面去,打印时只输出了一个对象,这是因为String它里面重写了hashCode()与equals()方法,所以解决刚才的问题就很简单了,我们只要在Student中重写hashCode()与equals()就可以了。在Student中加入如下代码:

        /**
	 * 重写hashcode方法
	 *
	 * @return
	 */
	 public int hashCode() {
	 return age * name.hashCode();
	 }
		
		
	 /**
	 * 重写equals方法
	 */
	 public boolean equals(Object obj) {
	 Student s = (Student) obj;
	 return age == s.age && name.equals(s.name);
	 }

最后测试结果是:
      2 yqq
     3 lz
     1 czc
     最后总结下equals()与对象的hash值的关系:
         a. equals()相等的两个对象,hashcode()一定相等;
        b. equals()方法不相等的两个对象,hashcode()有可能相等
如:Integer s1=new Integer(97);
   String s2 = new String("a");
                  它们是不等的,但它们的hashcode值都为97
        c.反过来,hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()不定相等,如上所示的例子
    
      对于原理性的东西,我也有很多不明白的地方,文章所写有些全为个人见解,难免会有理解偏差之处,希望高手不吝赐教。
4
2
分享到:
评论
3 楼 hold_on 2010-11-16  
 
2 楼 82934162 2010-11-12  
1 楼 qingBYqing 2010-11-11  
 

相关推荐

    去掉list中的重复对象

    "去掉list中的重复对象"这个话题是一个常见的需求,特别是在处理业务数据时,确保数据的唯一性至关重要。这篇博客文章《去掉list中的重复对象》可能是探讨了如何在Java中有效地实现这一功能。 在Java中,List接口...

    如何用Map对象创建Set对象Java开发Java经验技巧

    Map主要用于存储键值对,而Set则是一个不包含重复元素的集合。本篇将详细讲解如何利用Map对象来创建Set对象,这对于Java开发者来说是一个实用的经验技巧。 首先,我们需要理解Map与Set的基本概念。Map接口代表一个...

    c++ 类与对象课件,包括对象的初始化,对象的使用,构造函数和析构函数等等

    常对象(Const Object)是指声明为const的类对象,它的成员函数不能修改数据成员。常成员函数(Const Member Function)是在类定义中声明为const的函数,它承诺不修改对象的状态。 最后,对象在内存中的分布情况...

    set的用法的源代码资源

    通过以上介绍,我们对Python中的`set`有了全面的理解。在实际编程中,灵活运用这些知识能帮助我们编写更简洁、高效的代码。在提供的资源中,可能包含了更多关于`set`的实际示例和应用场景,建议进一步学习和实践。

    VB的GET SET方法批量生成加使用说明书

    例如,如果你有一个名为`Person`的对象,它有一个`Name`属性,那么`Person.Name`的读取操作会触发`Name`属性的GET过程。 SET方法则用来设置对象的属性值。当你为对象的属性赋值时,VB会调用相应的SET方法。这个过程...

    java List、Set与Array之间的相互转换

    7. **Java集合框架的理解**:了解Java集合框架的设计理念,如List接口实现了有序且允许重复的序列,Set接口实现了无序且不允许重复的集合,以及Array是固定大小的原始类型或对象的数组,有助于更好地理解这些转换...

    CustomSet.zip

    在Java编程语言中,HashSet是一种常用的集合类,它实现了Set接口,不包含重复元素,并且不保证元素的顺序。在给定的“CustomSet.zip”压缩包中,我们看到一个名为“CustomSet.java”的文件,这很可能是用户自定义的...

    Set用法及与List的区别

    首先,让我们理解Set的基本概念。Set是一个不允许有重复元素的集合,它遵循唯一性原则。在Set接口下有许多实现类,如HashSet、TreeSet和LinkedHashSet等。我们以`HashSetDemo.java`为例,探讨HashSet的使用方法。 `...

    java对象容器(涉及HashMap,ArrayList,Set等)

    Java对象容器是Java编程中不可或缺的部分,它们提供了一种存储和管理对象的方式,使得我们可以高效地组织和操作数据。在Java中,最常见的对象容器包括ArrayList、List、Set和HashMap等。这些容器各自具有不同的特性...

    java 运用集的相关类(Set)

    Set接口继承自Collection接口,其主要特性是元素的唯一性,即不允许有重复的元素。Set接口没有定义任何特定的存储行为,具体的行为由它的实现类来决定。Java提供了多种Set接口的实现,如HashSet、TreeSet和...

    collection,list,set,map

    - Map是一个存储键值对的对象,每一个键映射到一个值,且键值对之间不能有重复的键。Map中不允许重复的键,但可以重复的值。 虽然给定文件内容没有直接介绍这些集合,但这些是Java集合框架中最基础和最重要的知识点...

    c++类set精讲和详解

    一旦元素插入到`set`容器中,其值就不能被更改。 #### 二、set容器的基本特性 1. **动态大小**:`set`容器的大小可以根据需要动态变化。 2. **双向迭代器**:`set`容器提供了双向迭代器来访问容器中的元素。 3. **...

    js代码-去重:Set 对象 + Array.from

    然后,我们使用`Array.from`将这个`Set`对象转换回一个新的数组`uniqueArr`,这个数组不包含任何重复的元素。 这种方式的优点在于它简洁、高效,并且能保持原数组的顺序(因为`Set`的插入顺序是保留的)。此外,`...

    对参数 对象的理解方法

    ### 对参数与对象方法的理解 #### 一、参数与对象的基本概念 在计算机编程中,尤其是在面向对象的语言如Java中,参数与对象是两个非常重要的概念。为了更好地理解和使用它们,我们首先需要明确这两个概念的基本...

    set.list.map接口

    Set接口表示一个不包含重复元素的集合。在Java中,Set接口的主要实现类有HashSet和TreeSet。 - **HashSet**:基于哈希表实现,不保证元素的顺序,插入元素时不会进行排序,允许null元素。 - **TreeSet**:基于...

    python列表练习-列表如何去重(不使用用set或者dict)(csdn)————程序.pdf

    标题提到的“python列表练习-列表如何去重(不使用set或者dict)”是一个编程练习,目的是锻炼对列表操作的理解和技巧。描述中也明确了我们要避免使用set或dict,这两种数据结构在Python中是用于集合操作和键值对存储...

    java中list、set和map 的区别

    键必须是唯一的,而且不能为`null`。 - **TreeMap**: 这种实现通过红黑树来存储键值对,它能够按照键的自然顺序或者由比较器定义的顺序来排序键值对。与`HashMap`相比,`TreeMap`提供了额外的功能,如获取子图...

    STL_set.rar_stl set

    这个压缩包中的"STL_set"可能包含了关于如何使用`set`进行操作的示例代码,这对于理解和实践C++中的STL`set`容器非常有帮助。通过这些代码,你可以更深入地了解`set`的工作原理以及如何在实际项目中应用它。学习并...

    java中三种集合set、map、list的区别与联系

    `Set`是一种不允许重复元素的数据结构。这意味着`Set`中的所有元素都是唯一的,任何两个元素都不能相等(根据`equals()`方法判断)。`Set`的主要实现包括`HashSet`、`TreeSet`和`LinkedHashSet`。 - **`HashSet`**...

    Set数据结构.pdf

    Set数据结构是JavaScript中一种非常重要的数据组织方式,它的核心特性是存储的元素都是唯一的,不允许重复。在本文中,我们将深入探讨Set数据结构的定义、属性、方法以及如何进行遍历。 ### 定义与特点 Set数据结构...

Global site tag (gtag.js) - Google Analytics