如果要查找一个集合中是否包含了某个对象,那么就需要把这个对象和这个集合中的每个对象依次进行比较和判断,直到找到这个对象为止,或者把所有对象都比较一次为止(如果最后一个对象才是要查找的对象,或者集合中没有包含要查找的对象)。当集合中的对象数量较多时,效率就很低。为了提高效率,提出了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. eclipse启动不了

    因为eclipse运行变得非常慢,我想再次增加一下eclipse的最大内存,以期待使eclipse能够快速的响应. 参照某些资料,我也不知道什么时候改成了这样: -vmargs-Xms512m-Xmx ...

  2. DDD~WCF做中间件,实现多个项目的缓存共享

    回到目录 事情是这样的,前台网站有些数据不希望每次都从数据库里读,所以,应该做个缓存,而引起缓存更新的入口来自网站的后台管理,而前台和后台被部署在不同的网站中,这时缓存的更新就成了问题,前台的缓存与后 ...

  3. Docker镜像

    docker镜像123? 额,由于没有实验环境,没有亲手实践,因此理解可能有不对的地方. 反正也是学习笔记,以后再修改吧... docker的镜像跟virtualbox的镜像不一样.在虚拟机中,镜像是 ...

  4. Atitit  rgb yuv  hsv HSL 模式和 HSV(HSB) 图像色彩空间的区别

    Atitit  rgb yuv  hsv HSL 模式和 HSV(HSB) 图像色彩空间的区别 1.1. 色彩的三要素 -- 色相.明度.纯度1 1.2. YUV三个字母中,其中"Y&quo ...

  5. webService 基础

    一. 1. 定义:Web service是一个平台独立的,跨语言.跨平台.低耦合的,自包含的.基于可编程的web的应用程序,可使用开放的XML (标准通用标记语言下的一个子集)标准来描述.发布.发现. ...

  6. KnockoutJS 3.X API 第四章 表单绑定(10) textInput、hasFocus、checked绑定

    textInput绑定目的 textInput绑定主要用于<input>或者<textarea>元素.他提供了DOM和viewmodel的双向更新.不同于value绑定,tex ...

  7. transform你不知道的那些事

    transform是诸多css3新特性中最打动我的,因为它让方方正正的box module变得真实了. transform通过一组函数实现了对盒子大小.位置.角度的2D或者3D变换.不过很长时间内,我 ...

  8. Linux下程序包管理工具RPM

    实验环境: CentOS release 6.6 (Final)  一台 IP地址:172.16.249.230 RPM 是 Red Hat Package Manager 的缩写,本意是Red Ha ...

  9. javascript类型系统——undefined和null

    × 目录 [1]原因 [2]undefined [3]null 前面的话 一般的程序语言,表示空的只有null,但javascript的设计者Brendan Eich却设计了一个undefined,这 ...

  10. javascript运算符——算术运算符

    × 目录 [1]一元加 [2]一元减 [3]递增[4]递减[5]加法[6]减法[7]乘法[8]除法[9]求余 前面的话 javascript中的算术操作主要通过算术运算符来实现,本文将介绍算术运算符的 ...