如果要查找一个集合中是否包含了某个对象,那么就需要把这个对象和这个集合中的每个对象依次进行比较和判断,直到找到这个对象为止,或者把所有对象都比较一次为止(如果最后一个对象才是要查找的对象,或者集合中没有包含要查找的对象)。当集合中的对象数量较多时,效率就很低。为了提高效率,提出了Hash算法。Hash算法对每一个对象都计算出一个Hash码,根据Hash码把对象分配到某个存储区域中,比如一个集合包含了很多人,根据国籍,中国人是一个存储区域,美国人是一个存储区域,英国人是一个存储区域,......。这样如果要查找该集合是否包含了某个中国人,就到中国人的存储区域去比较就行了,这样大大提高了效率。

Java中实现了Hash的集合是HashSet。HashSet查找某个对象时,首先用hashCode()方法计算出这个对象的Hash码,然后再根据Hash码到相应的存储区域用equals()方法查找,从而提高了效率。由于是集合,所以同一个对象只能有一个。

hashSet的例子如下所示:

package my;

import java.util.HashSet;
import java.util.Set; class Person{ // 性别
String sex;
// 姓名
String name;
// 身高
Double hei;
// 体重
Double wei; public Person(String n, String s, Double h, Double w){
this.name=n;
this.sex=s;
this.hei=h;
this.wei=w;
} public String toString(){
return "\n姓名:"+this.name+" 性别:"+this.sex+" 身高:"+this.hei+" 体重:"+this.wei;
} } public class myHS { private static Set<Person> mySet = new HashSet<Person>();
public static void main(String[] args) {
mySet.add(new Person("Tom","Male",170.0,70.0));
mySet.add(new Person("Peter","Male",175.0,70.0));
mySet.add(new Person("Kate","Female",168.0,60.0));
mySet.add(new Person("Alice","Female",161.0,55.0));
mySet.add(new Person("Jack","Male",190.0,95.0));
mySet.add(new Person("Jack","Male",190.0,95.0));
System.out.println(mySet);
} }

以上例子先定义了Person类,然后定义了一个HashSet,并加入了5个Person到该集合,其中1个人加入了两次,运行结果如下:

可见Jack是同一个人,却在集合中出现了两次,这是什么原因呢?这是因为,Person是Object的子类,而Object类的equals()方法是根据对象的内存地址来判断两个对象是否相等的,由于两次插入的Jack的内存地址肯定不相同,所以判断的结果是不相等,所以两次都插入了。于是,我们需要覆写equals()方法来判断两个对象是否是同一个对象。

    // 覆写equals方法
public boolean equals (Object obj){
// 地址相等,则肯定是同一个对象
if(this==obj){
return true;
}
// 类型不同,则肯定不是同一类对象
if(!(obj instanceof Person)){
return false;
}
// 类型相同,向下转型
Person per=(Person) obj;
// 如果两个对象的姓名和性别相同,则是同一个人
if(this.name.equals(per.name)&&this.sex.equals(per.sex))
return true;
return false;
}

覆写equals()方法以后,运行结果如下:

可见Jack仍然被插入了两次,这是什么原因呢?这是因为Object的Hash码返回的是对象的Hash地址,而两个对象的Hash地址肯定是不相等的,所以6次插入的对象被存储在6个存储区域,equals()方法根本没有运行。于是,还需要覆写hashCode()方法,根据姓名来计算对象的Hash码。

    // 覆写hashCode方法
public int hashCode(){
return this.name.hashCode();
}

运行结果如下:

可见,Jack只插入了一次,终于正确了。如果根据性别来计算对象的Hash码,结果也是正确的,Jack也只会被插入1次。但是,如果两个对象的性别不同,如下所示:

        mySet.add(new Person("Jack","Male",190.0,95.0));
mySet.add(new Person("Jack","Female",190.0,95.0));

则两个对象都会被插入:

这是因为虽然两个对象的Hash码相同(不论是按照姓名,还是按照性别来计算,Hash码都是相同的),但是equals()方法判断这两个对象不相等,于是都插入了。

Java的HashSet类的更多相关文章

  1. JDK1.8源码(八)——java.util.HashSet 类

    在上一篇博客,我们介绍了 Map 集合的一种典型实现 HashMap ,在 JDK1.8 中,HashMap 是由 数组+链表+红黑树构成,相对于早期版本的 JDK HashMap 实现,新增了红黑树 ...

  2. Java API —— Set接口 & HashSet类 & LinkedHashSet类

    1.Set接口     1)Set接口概述         一个不包含重复元素的 collection,无序(存储顺序和取出顺序不一致),唯一.  (List有序,即存储顺序和取出顺序一致,可重复) ...

  3. Java——(三)Collection之Set集合、HashSet类

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 一.Set集合 Set集合不允许包含相同的元素,如果试图把两个相同的元素加入同一个Set集合中, ...

  4. Java集合概述、Set集合(HashSet类、LinkedHashSet类、TreeSet类、EnumSet类)

    Java集合概述.Set集合(HashSet类.LinkedHashSet类.TreeSet类.EnumSet类) 1.Java集合概述1)数组可以保存多个对象,但数组长度不可变,一旦在初始化数组时指 ...

  5. java——HashSet类中的常见方法

    package com.xt.set; import java.util.HashSet; import java.util.Iterator; import java.util.Set; publi ...

  6. Java 数据类型:集合接口Collection之Set接口HashSet类;LinkedHashSet;TreeSet 类

    Collection 之 Set 实现类: HashSet TreeSet 特点: 无序. 元素不可重复. (如果试图添加一个已经有的元素到一个Set集合中,那么会添失败,add()方法返回false ...

  7. JAVA Collections工具类sort()排序方法

    主要分析内容: 一.Collections工具类两种sort()方法 二.示例 一.Collections工具类两种sort()方法 格式一: public static <T extends ...

  8. Java集合---Array类源码解析

    Java集合---Array类源码解析              ---转自:牛奶.不加糖 一.Arrays.sort()数组排序 Java Arrays中提供了对所有类型的排序.其中主要分为Prim ...

  9. 【Java基础】类和接口

    Num1:使类和成员的可访问性最小化 要区别设计良好的模块与设计不好的模块,最重要的因素在于,这个模块对于外部的其他模块而言,是否隐藏其内部数据和其他实现细节.设计良好的模块会隐藏所有的实现细节,把它 ...

随机推荐

  1. (数学)P、NP、NPC、NP hard问题

    概念定义: P问题:能在多项式时间内解决的问题: NP问题:(Nondeterministic Polynomial time Problem)不能在多项式时间内解决或不确定能不能在多项式时间内解决, ...

  2. MVVM架构~knockoutjs系列之包括区域级联列表的增删改

    返回目录 这个例子我做了几次,之前总是有BUG,目前测试后,确定没有BUG才发上来的,主要功能是实现“我的银行”模块的增删改的功能,这个里面包括了级联列表的区域选择,这部分是难点,在开发过程中,我们应 ...

  3. iOS--二维码

    现在很多APP都涉及了二维码扫码功能,这个功能简单实用,很多情况下用户乐于使用,现在本文带来iOS7自带二维码扫码的教程,也包括扫条形码,足以满足简单的扫码要求,而且避免使用第三方的繁琐. 后期项目中 ...

  4. mysql-5.7.17-winx64免安装版,win10环境下安装配置

    下载地址:http://dev.mysql.com/downloads/file/?id=467269 1.解压到自定义目录:我解压到了D盘的根目录 2.复制my-default.ini 重命名 my ...

  5. java常用命令行指令

    javac 将java源文件编译成class字节码文件 javac HelloWorld.java java (1)运行class文件 java HelloWorld 注意java命令后面不要加.cl ...

  6. Ucos系统常用的数据结构有哪些?

    1)表 链表 表中主要了解链表,尤其是单向链表. 2)数组 一维数组 二维数组 使用数组有什么好处,在c语言中,数组是一组连续数字的集合它们数组的下标,代表了数组的相对位置,所以说,在一些高效的查表过 ...

  7. SSIS 对数据排序

    SSIS 对数据排序有两种方式,一种是使用Sort组件,一种是使用sql command的order by clause进行排序. 一,使用Sort组件进行排序 SortType:升序 ascendi ...

  8. KendoUI系列:DatePicker

    1.基本使用 <link href="@Url.Content("~/C ontent/kendo/2014.1.318/kendo.common.min.css" ...

  9. SQL*Loader之CASE5

    CASE5 1. SQL脚本 [oracle@node3 ulcase]$ cat ulcase5.sql set termout off rem host write sys$output &quo ...

  10. Unity 3D制作2D游戏的几种方法

    1.使用本身UGUI. 2.把摄像机的投影改为正交投影,不考虑Z轴. 3.使用Untiy自身的2D模式. 4.使用2D TooKit插件.