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上反复说明的,不过为什么要这样做呢?这两个方法之间有什么关系呢?本建议就来解释该问题,我们先 ...
随机推荐
- 【TCP】连接管理
TCP连接管理 本节将介绍一条TCP连接是如何建立和拆除的.此处假设客户机A上面的一个进程想要和服务 器B上的一个进程建立一条TCP连接.本文前面介绍的是比较正常的连接和拆除,特殊的会在后面介绍. ...
- 解读Position
首先Position在字面讲是位置的意思,在HTML中是定位的意思,它有四种属性:分别是static是静态的,也是默认的效果,没有特别的设定,遵循基本的定位规定,不能通过z-index进行层次分级. ...
- Layui 内置方法 - layer.prompt_(输入层)
prompt的参数也是向前补齐的.options不仅可支持传入基础参数,还可以传入prompt专用的属性.当然,也可以不传,yes携带value 表单值index 索引elem 表单元素. promp ...
- tensorflow.python.framework.errors_impl.PermissionDeniedError: /data; Permission denied
在linux系统中,tensorflow跑mnist数据集出现错误,本应该自动下载的数据集 将mnist自动下载的路径,由/data/mnist之前的/删掉即可.改为data/mnist.
- onpageshow、onpagehide、onload、onunload
onpageshow :在用户浏览网页时触发, 在页面从浏览器缓存中读取时也触发 通过event.persisted 来判断, 如果页面从浏览器的缓存中读取该属性返回 ture,否则返回 false ...
- Codeforces Round #512 (Div. 2, based on Technocup 2019 Elimination Round 1) E. Vasya and Good Sequences(DP)
题目链接:http://codeforces.com/contest/1058/problem/E 题意:给出 n 个数,对于一个选定的区间,区间内的数可以通过重新排列二进制数的位置得到一个新的数,问 ...
- 洛谷P1363 幻想迷宫【dfs】
题目:https://www.luogu.org/problemnew/show/P1363 题意: 有一个地图,起点是S,障碍物用#表示.可以将这个地图不断的在四周重复,问从起点开始是否可以走到无限 ...
- webstorm 2016.3 注册方法
用license server 的方式吧,activation code 的方式没有找到方法. license server 里写http://idea.iteblog.com/key.php 用li ...
- SSL虚拟主机
1.生成公钥与私钥 [root@proxy ~]# cd /usr/local/nginx/conf [root@proxy ~]# openssl genrsa > cert.key //生成 ...
- 单例模式(Singleton)---创建型
1 单例模式的使用场景 (1)当创建一个对象所占用的资源很多,但同时又需要使用到该对象 (2)当堆系统内的资源要求统一读写时,比如读写的配置信息,此时必须要求创建的实例信息相同 (3)当有多个实例可能 ...