HashSet如何保证元素唯一性的原理

1.HashSet原理

a. 我们使用Set集合都是需要去掉重复元素的, 如果在存储的时候逐个equals()比较, 效率较低,哈希算法提高了去重复的效率, 降低了使用equals()方法的次数

b. 当HashSet调用add()方法存储对象的时候, 先调用对象的hashCode()方法得到一个哈希值, 然后在集合中查找是否有哈希值相同的对象

c. 如果没有哈希值相同的对象就直接存入集合

d.如果有哈希值相同的对象, 就和哈希值相同的对象逐个进行equals()比较,比较结果为false就存入, true则不存

2.将自定义类的对象存入HashSet去重复

a. 类中必须重写hashCode()和equals()方法

b. hashCode(): 属性相同的对象返回值必须相同, 属性不同的返回值尽量不同(提高效率)

c. equals(): 属性相同返回true, 属性不同返回false,返回false的时候存储

必须重写hashCode()和equals()方法(当hash值相同时就会自动调用equals方法来判断两个对象是否相同)

注意: 当没有在Person类中重写hashCode()方法和equals()方法时, 则运行结果会出现相同的信息, 因为HashSet虽然会保证元素不可重复, 但是需要依据hashCode()方法和equals()方法 , 因为Person类中未重写这两个方法, 但是会使用Person类中从Object类里继承的hashCode()和equals(), 然而Object中的hashCode()比较的是对象的地址, 而每new出一个对象地址总是不同的, 所以会出现存储相同的元素.

Person实体类:

package online.msym.bean;
public class Person {
private String name;
private int age;
public Person() {
super();
}
public Person(String name, int age) {
super();
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;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
@Override
public boolean equals(Object obj) {
System.out.println("equals:执行了");
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age;
}
@Override
public int hashCode() {
System.out.println("hashCode :执行了");
        //这里一直返回10是为了证明hashSet集合判断元素对象是否相同,会先执行hashCode方法,返回值相同时,会再去调用对象的equals方法
return 10;
}
}

测试类:

package online.msym.mytest;
import java.util.HashSet;
import online.msym.bean.Person;
public class Demo1_HashSet {
/**
* 注意:我们认为姓名和年龄都相同时表示时同一个人
* 如果:Person类中没有重写equals方法的话,无法去重,但是重写后还是无法去除重复的内容
* 因为HashSet判断元素是否重复,首先根据元素的hashCode值,而我们并没有重写Person类的hashCode方法,
* 此时调用的是Object中的hashCode方法,而此方法是根据对象的地址值计算hashCode值,而只要是new出来的对象,
* 地址值肯定不同,所以计算出来的hashCode值也不相同,就认为不是同一个对象,也不会执行equals方法
* 如果我们重写了hashCode方法,先简单的返回一个数字10,这样当判断hashCode相等时就会去判断equals方法的返回值,
* 就能够去除重复
* @param args
*/
public static void main(String[] args) {
HashSet<Person> hs = new HashSet<>();
hs.add(new Person("张三", 23));
hs.add(new Person("张三", 23));
hs.add(new Person("李四", 24));
hs.add(new Person("李四", 24));
hs.add(new Person("李四", 24));
hs.add(new Person("李四", 24)); //System.out.println(hs.size());
System.out.println(hs);
}
}

修改后的Person实体类:实现Compareable接口,就具备了比较的功能了。

package online.msym.bean;
public class Person implements Comparable<Person> {
private String name;
private int age;
public Person() {
super(); }
public Person(String name, int age) {
super();
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;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
/*@Override
public boolean equals(Object obj) {
System.out.println("执行了吗");
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age;
}
@Override
public int hashCode() {
//40+23 39+24
//return name.hashCode()+age;
final int NUM = 38;
return name.hashCode() * NUM + age;
}*/
//Eclipse帮我们自动生成的hashCode和equals方法如下,alt+shift+s->h
/*
* 为什么是31?
* 1,31是一个质数,质数是能被1和自己本身整除的数
* 2,31这个数既不大也不小
* 3,31这个数好算,2的五次方-1,2向左移动5位
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) //调用的对象和传入的对象是同一个对象
return true; //直接返回true
if (obj == null) //传入的对象为null
return false; //返回false
if (getClass() != obj.getClass()) //判断两个对象对应的字节码文件是否是同一个字节码
return false; //如果不是直接返回false
Person other = (Person) obj; //向下转型
if (age != other.age) //调用对象的年龄不等于传入对象的年龄
return false; //返回false
if (name == null) { //调用对象的姓名为null
if (other.name != null) //传入对象的姓名不为null
return false; //返回false
} else if (!name.equals(other.name)) //调用对象的姓名不等于传入对象的姓名
return false; //返回false
return true; //返回true
}
}

【点击此处回到主页】

集合框架(HashSet存储自定义对象保证元素唯一性)的更多相关文章

  1. 集合框架-HashSet存储自定义对象

    1 package cn.itcast.p4.hashset.test; 2 3 import java.util.HashSet; 4 import java.util.Iterator; 5 6 ...

  2. Java基础知识强化之集合框架笔记40:Set集合之HashSet存储自定义对象并遍历

    1. HashSet存储自定义对象并遍历 2. 代码示例: (1)Student类,如下: package cn.itcast_02; /** * @author Administrator * */ ...

  3. Java基础知识强化之集合框架笔记41:Set集合之HashSet存储自定义对象并遍历练习

    1. HashSet集合存储自定义对象并遍历.如果对象的成员变量值相同即为同一个对象 注意了: 你使用的是HashSet集合,这个集合的底层是哈希表结构. 而哈希表结构底层依赖:hashCode()和 ...

  4. 30.1 HashSet存储自定义对象 未去重解决

    问题: package day30_HashSet; import java.util.HashSet; /* * 通过hashset存储自定义对象,没有进行去重. * * */ public cla ...

  5. Java基础知识强化之集合框架笔记45:Set集合之TreeSet存储自定义对象并遍历练习1(自然排序:Comparable)

    1. 自然排序: TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间的大小关系,然后将集合元素按照升序排列,这种方式就是自然排序. Java中提供了一个Comp ...

  6. Java基础知识强化之集合框架笔记46:Set集合之TreeSet存储自定义对象并遍历练习2(自然排序:Comparable)

    1. TreeSet存储自定义对象并遍历练习2: (1)Student.java package cn.itcast_06; /* * 如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口 * ...

  7. 用HashSet存储自定义对象

      案例 package cn.itcast_02; import java.util.HashSet; /* * 需求:存储自定义对象,并保证元素的唯一性 * 要求:如果两个对象的成员变量值都相同, ...

  8. 《java入门第一季》之HashSet存储自定义对象问题以及注意事项

    上一篇http://blog.csdn.net/qq_32059827/article/details/51578158 写到存储字符串类型的时候出现了无序,而且这个无序不是随机那种无序,它是有一定存 ...

  9. 《java入门第一季》之TreeSet存储自定义对象并保证排序和唯一

    上一篇用一个简单的例子,介绍了treeset集合存储的内部过程,这里再完善其存储自定义对象保证唯一. 需求:A:  * 自然排序,按照年龄从小到大排序  *         B:  * 成员变量值都相 ...

随机推荐

  1. 前端javascript基础总结(1)js的构成以及数据类型

    在日常工作中用到的原生js很少,感觉自己已经把原生的js忘光了,在这里开始总结下js,就从最基础的开始吧!!! JavaScript的组成: 1.ECMAScript:解释器,翻译. 个人理解为就是解 ...

  2. MyEclipse-Initializing Java Tooling问题

    问题描述: 今天早上打开Eclipse,打开Package Explorer 中项目时,总出现卡死现象. MyEclipse状态栏显示两个任务,(1) Checking for Updates (2) ...

  3. C++编程练习(10)----“图的最小生成树“(Prim算法、Kruskal算法)

    1.Prim 算法 以某顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树. 2.Kruskal 算法 直接寻找最小权值的边来构建最小生成树. 比较: Kruskal 算法主要是针对边来展开,边数 ...

  4. setObject:forKey和setValue:forKey的区别

    setObject:forKey: 是NSMutableDictionary类的方法                              key参数类型可以是任意类型对象             ...

  5. HTML5 技术在风电、光伏等新能源领域的应用

    随着新一轮工业革命兴起,应对气候变化日益成为全球共识,能源技术正在成为引领能源产业变革.实现创新驱动发展的源动力.从全球到中国,以风能.光伏发电为代表的新能源产业发展迅速,可再生能源发电与现代电网的融 ...

  6. JAVA中浮点数显示

    //Java小数点后留两位 double num1 =11; double num2 =21; String num3 =""; //函数可以确定十进制数的显示格式:百分数,限定小 ...

  7. C语言 extern学习2 分析

    上一篇文章中,通过头文件声明,而调用有一个特别大的漏洞: 为什么编译器可以链接过来呢,因为默认是extern修饰的,这种类似全局作用域的功能使其可以被调用 继续加强学习: 这一次有两对C文件: fir ...

  8. Docker网络代理设置

    背景 在一些实验室环境,服务器没有直接连接外网的权限,需要通过网络代理.我们通常会将网络代理直接配置在/etc/environment./etc/profile之类的配置文件中,这对于大部分操作都是可 ...

  9. Javascript面对对象. 第三篇

    3.字面量 为了让属性和方法很好的体现封装的效果,并且减少不必要的输入原型的创建可以使用字面量. function Box(){} //使用字面量的方法创建原型对象,这里的{}就是对象,是Object ...

  10. IE8上传文件时javascript读取文件的本地路径的问题("C:\fakepath\")的解决方案

    <script type="text/javascript"> function getPath(obj) { if (obj) { ) { obj.select(); ...