List去重为什么要写equals(),hashCode()方法
一,各个集合的特点:
- Collection(集合):容器,用于存放对象(引用类型。基本类型需要自动装箱)
- List(列表):元素有序,元素可以重复 (有索引)。 通过元素的equals()方法判断是否重复。
- Set(集):元素无序,不可重复 (没有索引)。 遍历只能用Iterator迭代器和增强for, 不能使用普通for遍历。
- ArrayList(数组列表): 查询快,增删慢。
- LinkedList(链表): 查询慢,增删快。
- HashSet(哈希表): 查询快,增删慢。 (底层其实就是Map) 。 存放的引用类型需重写hashCode()和equals()方法。
- LinkedHashSet(哈希链表): 查询慢,增删快。 有序的,存放顺序和取出顺序一致。
1.1,为什么要去重:
- 在我们开发中,我们所读取的数据难免会有重复数据,我们需要的则是不重复数据的引用,所以需要对数据进行去重,
- 而基本数据类型的去重比较好去重而引用数据类型呢,因为要判断hashCode运算是否相等,还有equals()是否相等,所以需要去重操作,
- 我们以一个list集合为例,在该例中,我们将User实体类中姓名和电话号码作为判断该对象重复的标识,在User的实体类中我们重写
- 这两个方法如下:
package com.example.pojo;
public class User {
private String name;
private String region;
private Integer performance;
public User(String name, String region, Integer performance) {
super();
this.name = name;
this.region = region;
this.performance = performance;
}
@Override
public String toString() {
return "User [name=" + name + ", region=" + region + ", performance=" + performance + "]";
}
@Override
public int hashCode() {
final int prime = ;
int result = ;
result = prime * result + ((name == null) ? : name.hashCode());
result = prime * result + ((performance == null) ? : performance.hashCode());
result = prime * result + ((region == null) ? : region.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;
User other = (User) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (performance == null) {
if (other.performance != null)
return false;
} else if (!performance.equals(other.performance))
return false;
if (region == null) {
if (other.region != null)
return false;
} else if (!region.equals(other.region))
return false;
return true;
}
}
- 以上实体类中,我们在equals()方法中取出该对象的name与region和performance这三个属性值去判断比较,然后在重写的hashCode()
- 方法中返回这三个属性值得equals对象地址值。
1.2,去重操作步骤:
package com.example.arraylist; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.example.pojo.User; /**
* @author Administrator
* 思路:
* 1.先对其文本文本进行添加,添加到List<User>中
* 2.把List<User>用迭代器进行迭代
* 3.创建一个新的集合,用来存储不重复的元素
* 4.用while(it.hasNext())有多少元素就循环多少次
* 4.判断新的集合是否有旧的元素如果没有则进行添加
*/
public class ListUserRepeat {
public static void main(String[] args) {
String string="张三,河北,90\n"+
"张三,河南,92\n"+
"李四,湖北,80\n"+
"王五,山西,88\n"+
"张三,河北,90\n"+
"李四,湖北,80\n"+
"马六,山东,77\n";
List<User> list = new ArrayList<>();
String[] split = string.split("\n");
for(String spl : split) {
String[] split2 = spl.split(",");
list.add(new User(split2[], split2[],Integer.parseInt(split2[])));
}
Iterator<User> it = list.iterator();
List<User> listOne = new ArrayList<>();
while(it.hasNext()) {
Object object = it.next();
if(!listOne.contains(object)) {
listOne.add((User) object);
}
}
for (User user : listOne) {
System.out.println(user);
}
}
}
运行这段代码之后,就会很明显的发现,list中重复的用户名,地区,都相同的对象就被会认为是重复的元素而删除掉,很明显运行结果已经达到我们的目的。
二,说一下为什么需要重写equals()方法和hashChode方法():
- 一般情况下我们重写equals()方法的时候还要重写hashChode()方法,但是我们用的是list所以不用重写hashCode,大家不妨
- 可以试试上面的例子,在实体类将重写的equals()方法注释掉,再运行程序,这时就会发现运行结果并不是我们刚刚得到的结果,(图中 我用的是list集合,
- 不是set集合,list集合只需要重写equals()方法就行,而set集合则equals()和hashCode()方法都需要重写)
2.1,String类中的equals()方法的源码如下:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = ;
while (n-- != ) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
通过观察equals()方法的源码我们可以看出,该方法去比较两个对象时,首先先去判断两个对象是否具有相同的地址,如果是同一个对象的引用,则直接放回true;如果地址不一样,则证明不是引用同一个对象,接下来就是挨个去比较两个字符串对象的内容是否一致,完全相等返回true,否则false。
2.2,String类中hashCode()方法的源码如下:
public int hashCode() {
int h = hash;
if (h == && value.length > ) {
char val[] = value;
for (int i = ; i < value.length; i++) {
h = * h + val[i];
}
hash = h;
}
return h;
}
以上是String类中重写的hashCode()方法,在Object类中的hashCode()方法是返回对象的32位JVM内存地址,也就是说如果我们不去重写该方法,将会返回该对象的32位JVM内存地址,以上我们测试的例子中,当注释掉重写的hashCode()方法时,这时默认返回对象的32JVM中的地址,两个不同的对象地址显然是不同的,我们在比较时,虽然通过重写的equals()方法比较出来name和phoneNumber值是相同的,但是默认的hashCode()方法返回的值他们并不是同一个对象,所以我们通常要将hashCode()方法与equals()方法一起重写,以维护hashCode方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
总结:
用白话说,通过hashCode判断对象是否放在同一个桶里,先确定他们在一个桶里面,然后再通过equals方法去判断这个桶里的对象是不是相同的。
List去重为什么要写equals(),hashCode()方法的更多相关文章
- equals(),hashcode()方法详解
Java中的equals方法和hashCode方法是Object中的,所以每个对象都是有这两个方法的,有时候我们需要实现特定需求,可能要重写这两个方法,今天就来介绍一些这两个方法的作用. equals ...
- Effective Java 第三版——11. 重写equals方法时同时也要重写hashcode方法
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- 如何编写出高质量的 equals 和 hashcode 方法?
什么是 equals 和 hashcode 方法? 这要从 Object 类开始说起,我们知道 Object 类是 Java 的超类,每个类都直接或者间接的继承了 Object 类,在 Object ...
- Java基础知识点2:hashCode()方法
hashCode()方法基本实现 hashCode方法是Java的Object类所定义的几个基本方法之一.我们可以深入到Object类的源码中去查看: public native int hashCo ...
- java中的 equals + hashCode
[0]README 0.1)本文转自 core java volume 1, 旨在理清 equals + hashCode方法: [1]equals方法 1.1) Object中的 equals 方法 ...
- equals(),hashcode(),克隆学习心得
equals(),hashcode(),克隆学习心得 其实在开发时候,很少去重写equals(),hashCode()方法,但是有些时候业务需要还是要重写. 注意: 重写equals()方法一定要重写 ...
- 千万不要误用 java 中的 HashCode 方法
刚才debug追堆栈的时候发现一个很奇怪的问题 我用IE8和Google的浏览器访问同一个地址 Action的 scope="session" 也设置了 而且两个浏览器提交的参数m ...
- JavaSE的包装类,自动装箱和自动拆箱 ,字符窜转换,toString(),equals(), hashCode()的区别
一.基本数据类型和包装类 包装类均位于Java.lang包,包装类和基本数据类型的对应关系如下表所示: Primitive-Type Wrapper-Class byte ...
- [改善Java代码]覆写equals方法必须覆写hashCode方法
覆写equals方法必须覆写hashCode方法,这条规则基本上每个Javaer都知道,这也是JDK API上反复说明的,不过为什么要这样做呢?这两个方法之间有什么关系呢?本建议就来解释该问题,我们先 ...
随机推荐
- python totp代码
import time import datetime import math import hmac import base64 import qrcode from PIL import Imag ...
- CentOs Linux 对于 修改 yum源 为 阿里
修改yum源为阿里 备份本地yum源 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo_bak 2.获取阿里 ...
- MongoDB安全运维
0×00 MongoDB权限介绍 1.MongoDB安装时不添加任何参数,默认是没有权限验证的,登录的用户可以对数据库任意操作而且可以远程访问数据库,需以–auth参数启动. 2.在刚安装完毕的时候M ...
- C#中怎么将XML作为参数post到接口
String xml = "<data>中文</data>"; String postData = "data=" + Server.U ...
- systemctl automatically restart service
systemctl automatically restart service Pothi Kalimuthu Linux October 9, 2016 0 Minutes Reference ...
- Git远程分支和refs文件具体解释
推送远程分支到同一个server 比方首先建立gitserver,顺便clone出两个副本 mkdir server cd server git init --bare cd .. git clone ...
- linux基础_用户管理
1.创建用户 基本语法 创建用户:useradd [选项] 用户名 (1)当传教用户成功后,会自动的创建和用户名同名的家目录. (2)也可以通过useradd -d 指定目录 新用户名,给新创建的用户 ...
- CF700E Cool Slogans——SAM+线段树合并
RemoteJudge 又是一道用线段树合并来维护\(endpos\)的题,还有一道见我的博客CF666E 思路 先把\(SAM\)建出来 如果两个相邻的串\(s_i\)和\(s_{i+1}\)要满足 ...
- Python 字典 (4) 持续更新
字典一种用名字来引用值的数据结构,这种数据结构称为 映射(mapping) .字典中的键可以是数字.字符串和元组. 字典 创建和使用 创建 phonebook = {'Aaron':133000000 ...
- CodeForces 835C - Star sky | Codeforces Round #427 (Div. 2)
s <= c是最骚的,数组在那一维开了10,第八组样例直接爆了- - /* CodeForces 835C - Star sky [ 前缀和,容斥 ] | Codeforces Round #4 ...