首先我们自定义Person类,只有姓名和年龄两个属性

class Person{
private String name ;
private int age ;
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 "[name=" + name + ", age=" + age + "]";
}
}

创建HashSet,元素为Person对象

public class SetDemo1 {
public static void main(String args[]) {
Set<Person> mySet = new HashSet<>();
mySet.add(new Person("唐三",20)) ;
mySet.add(new Person("唐三",20)) ;
mySet.add(new Person("小舞",19)) ;
System.out.println(mySet);
}
}

运行结果:



相同的人存进Set里了,这似乎与Set不存储相同元素的特点相悖。

实质上当执行第一个mySet.add(new Person(“唐三”,20))时,Person对象会被自动分配一个hashcode。执行第二个mySet.add(new Person(“唐三”,20))时Person对象会得到一个不同hashcode,这个hashcode到底从哪来我们可以看下源码



这个map是HashMap,可见Set底层由Map实现,不过这里并没有求hashcode,继续看此put的源码



这里显示求出键key的hash值,也就是我们所存入对象的hash值。有兴趣的可以继续往下看底层实现。

由于hashcode不同,所以第二个Person对象可以加入Set集合。如果两对象的hashcode相同就会调用euqals()方法。我们修改代码的思路应该是覆写hashCode方法,让有相同姓名年龄的Person的hashcode相同,同名同龄为同一个Person对象是我们人为规定的,所以我们还要覆写Person的equals()方法让它知道这个规定。(在Eclipse里通过alt+shift+s+h可以快速添加hashCode和equals方法)

Person类代码修改为:

class Person{
private String name ;
private int age ; 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;
}
public String toString() {
return "[name=" + name + ", age=" + age + "]";
}
@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;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}

再次运行SetDemo1结果:



这样就确保了HashSet里自定义对象的唯一性,关键就是覆写自定义对象的hashCode()和equals()。

上述代码中hashCode()和equals()是使用eclipse快速构建的。为什么hashCode()方法要那样写呢?实质上写成

public int hashCode() {
return age+name.hashCode();
}

也可以。但是这样有个弊端就是假设HashSet里有一个Person,名字哈希码是30,年龄20,要加入的Person名字哈希码为29,年龄21,这样就造成虽然两Person对象不同,但后者无法存入。为降低hashcode重复的几率,就将年龄与名字的哈希码进行一定规律的变化。

至于为什么prime是31也有讲究

  1. 31是一个质数,公约数少。
  2. 31大小适中。太大的话经过一系列乘加可能超出int取值范围,太小重复几率就高了。
  3. 31是25-1,好算

JavaSE 集合类HashSet保证自定义对象唯一性的更多相关文章

  1. JavaSE 集合类TreeSet存储自定义对象

    文章目录 一.自动排序功能测试 二.对自定义类的自动排序 一.自动排序功能测试 public class TreeSetDemo { public static void main(String ar ...

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

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

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

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

  4. 用HashSet存储自定义对象

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

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

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

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

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

  7. 集合框架(HashSet存储自定义对象保证元素唯一性)

    HashSet如何保证元素唯一性的原理 1.HashSet原理 a. 我们使用Set集合都是需要去掉重复元素的, 如果在存储的时候逐个equals()比较, 效率较低,哈希算法提高了去重复的效率, 降 ...

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

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

  9. JAVA之旅(二十)—HashSet,自定义存储对象,TreeSet,二叉树,实现Comparator方式排序,TreeSet小练习

    JAVA之旅(二十)-HashSet,自定义存储对象,TreeSet,二叉树,实现Comparator方式排序,TreeSet小练习 我们继续说一下集合框架 Set:元素是无序(存入和取出的顺序不一定 ...

随机推荐

  1. Caused by: javax.persistence.NonUniqueResultException: result returns more than one elements

    Caused by: javax.persistence.NonUniqueResultException: result returns more than one elements at org. ...

  2. Rsync + Lsyncd服务实现文件实时同步/备份

    1.接受端安装rsync yum -y install rsync 2.配置同步模块 vim /etc/rsyncd.conf # any name you like [backup] # desti ...

  3. wget -r -c -nd

    wget -r -c -nd -r 递归下载 -c 断点续传 -nd 不创建目录, wget默认会创建一个目录 -l1 (L one) 递归一层,只下载指定文件夹中的内容, 不下载下一级目录中的.–n ...

  4. windows安装composer

    Composer 是 PHP 的一个依赖管理工具(不是一个包管理器).它允许你申明项目所依赖的代码库,它会在你的项目中为你安装他们. 在windows下安装的方法 方法一:使用安装程序 这是将 Com ...

  5. linux下open-vswitch安装卸载操作

    一. ovs 从源码编译安装: 安装依赖项: ? 1 2 3 4 5 6 7 8 9 10 11 # apt install make # apt install gcc # apt install ...

  6. R和Python,对抗or融合?

    来源商业新知网,原标题:从对抗到融合,教你充分利用R+Python! 我们应该将关注点放在技能上,而不是工具上. 如果你从事数据科学的工作,可能会立即想到两种编程语言:R和Python. 事实上,R和 ...

  7. Django中的auth模块

    from django.contrib import auth authenticate() 提供了用户认证功能,即验证用户名以及密码是否正确,一般需要username .password两个关键字参 ...

  8. Python学习—框架篇之初识Django

    什么是web框架? 框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以帮你快速开发特定的系统,简单地说,就是你用别人搭建好的舞台来做表演. 对于所有的W ...

  9. SourInsight4 配置视野内引用高亮

  10. excle 内部 超链接(锚点)

    超连接对象: 1.文档 2.本文档中的位置. 3.  本文重点  指定 链接到 xx表中的xx位置. 第三种连接  类似于 web文档的中 锚点 超连接 看下图 选 择本文档中的位置, 选择 工作表. ...