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上反复说明的,不过为什么要这样做呢?这两个方法之间有什么关系呢?本建议就来解释该问题,我们先 ...
随机推荐
- asp.net使用FileUpload控件上传图片且重命名
我在根目录下创建了一个Images图片存放文件夹,上传的图片都在这 下面贴代码 if (FileUpload1.HasFile) { string filename = FileUpload1.Fil ...
- java—锁的学习研究
摘抄自博客:https://www.cnblogs.com/qifengshi/p/6831055.html 标题:Java中的锁分类 锁的分类: 公平锁/非公平锁 可重入锁 独享锁/共享锁 互斥锁/ ...
- Python正则及geometer正则截图讲解
正则表达式 语法: 1 2 3 4 5 6 import re #导入模块名 p = re.compile("^[0-9]") #生成要匹配的正则对象 , ^代表从开头匹 ...
- 获取DataFrame列名的3种方法
df= pd.DataFrame({'a': range(10, 20), 'b': range(20, 30)}) df 1.链表推倒式 [column for column in df][a,b] ...
- SQL Server查询表结构语句
--1:获取当前数据库中的所有用户表 www.2cto.com select Name from sysobjects where xtype='u' and status>=0 -- ...
- HDU 6051 - If the starlight never fade | 2017 Multi-University Training Contest 2
/* HDU 6051 - If the starlight never fade [ 原根,欧拉函数 ] | 2017 Multi-University Training Contest 2 题意: ...
- vue 日期格式化过滤器
formateDate日期格式化,写在公共的js中: export function formateDate(date, fmt){ if ('/(y+)/'.test(fmt){ fmt = fmt ...
- ros中同时订阅两个topic(2张图像)合并成一个topic(1张图像)
2019-12-06 15:42:39 先暂时做个资料保存 要同时用两个红外相机,但是没有做硬件上的 时间戳同步,就是笔记本上同时插着两个相机. 两个topic发布各自相机的图像,然后要有个节点同时订 ...
- JAVA的面向对象1
如何理解面向对象 我们说面向对象具有三大特征:封装性.继承性和多态性,那么我们怎么去理解所谓的封装.继承.多态? 1.封装:功能都给你做好了,你不必去理解它是怎么写出来的,直接使用即可. 如:房子.电 ...
- 小程序和vue的区别
最近开发了一个比较完整的小程序项目,打算总结一下,小程序开发和vue开发的代码上的区别 1.小程序的路由写在app.json文件里,vue写在route.js里 2.小程序用 src="{{ ...