引言

在Collection集合中:
contains方法是判断一个集合里面是否包含指定元素,如果有则返回true;
remove方法是从集合中删除指定元素的单个实例;
这两个方法看起很简单,用起来也很简单,同样也非常常用;但是,它们到底是怎么匹配到相应的元素呢?

源码剖析

以ArrayList为例,我们分析一下ArrayList中的contains和remove的源码;

先看看contains:

这里看到比较的对象是一个Object类,变量名为 o(就是是否包含 o ),并且调用了一个indexOf方法,接下来我们进一步看看indexOf源码:

可以看到,indexOf又进一步调用了indexOfRange方法,我们还需要深入看看这个方法:

这里可以发现,indexOfRange中 o 调用了equals方法(蓝色部分)!
我们知道:equals方法是判断两个对象是否相等,但是默认情况下比较的是对象的地址,如果想要比较对象的内容就需要重写equals方法;
那么这个contains调用了equals方法,所以,contains判断一个集合中是否包含某个元素其实就是通过对象地址比较的了;
这并不是我们想要的结果,所以几乎所有放在集合中的类型,都需要重写equals方法!

为什么是几乎所有?
因为还是有特例的:SUN公司已经把String类和包装类的equals方法重写了,所以对于这两种我们不需要重写equals!

同样看看remove方法:

同样,remove方法也是通过equals方法比较元素然后移除的;

所以这里可以得出一个结论:
Collection集合中的remove方法和contains方法底层都会调用equals,所以只要放在集合中的类型,都要重写equals方法
因为对对象的地址的比较没有什么意义,我们实际上需要的是对象内容间的比较;

实例测试

知道了结论,就来写几个代码测试一下:

String类和包装类的特殊情况

对于 String类型和包装类,SUN公司重写了equals方法,所以我们先测试一下这两种情况:

import java.util.ArrayList;
import java.util.Collection;// 结论:Collection接口中的remove方法和contains方法底层都会调用equals,
// 所以存放在一个集合中的类型,要重写它的equals方法
// (但是String和包装类的equals方法已经重写过了,不用重写)
public class CollectionTest02 {public static void main(String[] args) {// 这里以ArrayList为例Collection array1 = new ArrayList();// String类:String s1 = "Hello";// 将s1放入array1array1.add(s1);// 定义一个s2也为 "Hello",那么调用contains是否会包含s2?String s2 = "Hello";System.out.println("array1是否包含s2?" + array1.contains(s2)); // true// 因为array1中放入的是s1,如果移除s2,s1会不会被移除呢?array1.remove(s2);System.out.println("移除s2后s1是否还在array1中?" + array1.contains(s1)); // false// 包装类也同样:Integer num1 = 1000;// 将num1放入array1array1.add(num1);// 定义一个num2也为1000Integer num2 = 1000;System.out.println("array1是否包含num2?" + array1.contains(num2)); // true// 移除num2观察num1是否会被移除array1.remove(num2);System.out.println("移除num2后num1是否还在array1中?" + array1.contains(num1)); // false}
}

输出结果:

array1是否包含s2?true
移除s2后s1是否还在array1中?false
array1是否包含num2?true
移除num2后num1是否还在array1中?false

自定义类型

这是equals重写的情况,接下来我自定义一个类型,看看没有重写会发生什么;

import java.util.ArrayList;
import java.util.Collection;public class CollectionTest03 {public static void main(String[] args) {// 还是以ArrayList为例Collection array = new ArrayList();// 创建一个User对象u1User u1 = new User("张三");// 将u1对象放入array中array.add(u1);// 再创建一个User对象,使其内容和u1相同都为"张三",那么调用contains是否会包含该对象呢?System.out.println("array中是否包含新创建的对象?" + array.contains(new User("张三"))); // false// 移除一个内容为"张三"的新的对象,u1是否会被移除?array.remove(new User("张三"));System.out.println("移除后u1是否存在?" + array.contains(u1)); // true}
}// 自己定义一个User类
class User {// 成员变量:姓名private String name;// 默认构造User() {}// 有参构造:初始化姓名User(String name) {this.name = name;}
}

输出结果:

array中是否包含新创建的对象?false
移除后u1是否存在?true

可以看到,我自定义的User方法里没有重写equals方法,所以当调用contains和remove时,虽然传入的对象内容和u1的对象内容相同都为“张三”,但是实际上比较的却是对象的地址;

接下来我重写User的equals方法,看看结果如何;

import java.util.ArrayList;
import java.util.Collection;public class CollectionTest03 {public static void main(String[] args) {// 还是以ArrayList为例Collection array = new ArrayList();// 创建一个User对象u1User u1 = new User("张三");// 将u1对象放入array中array.add(u1);// 再创建一个User对象,使其内容和u1相同都为"张三",那么调用contains是否会包含该对象呢?System.out.println("array中是否包含新创建的对象?" + array.contains(new User("张三"))); // true// 移除一个内容为"张三"的新的对象,u1是否会被移除?array.remove(new User("张三"));System.out.println("移除后u1是否存在?" + array.contains(u1)); // false}
}// 自己定义一个User类
class User {// 成员变量:姓名private String name;// 默认构造User() {}// 有参构造:初始化姓名User(String name) {this.name = name;}// 重写equals方法 ,通过name进行比较public boolean equals(Object o) {if (this == o) return true;if (!(o instanceof User)) return false;User user = (User) o;return name.equals(user.name);}
}

输出结果:

array中是否包含新创建的对象?true
移除后u1是否存在?false

我只是重写了一个equals方法,其他地方都没变,结果完全不同;

所以这就验证了之前的结论:contains 和 remove 底层实现都调用了equals方法

总结

其实这篇文章就是分析一下contains 和 remove 底层实现,主要想说的还是那一句话:
Collection集合中的remove方法和contains方法底层都会调用equals,所以只要放在集合中的类型,都要重写equals方法;(String和包装类除外)

希望各位在Java学习中养成好习惯,要时刻惦记着equals的重写,不然如果做了一个项目你连错在哪里都不好找到;

Collection集合中的 contains 和 remove 使用深入——为什么要重写equals() ?相关推荐

  1. Java中Collection集合常用API - Collection存储自定义类型对象

    文章目录 Collection常用API Collection存储自定义类型对象 Collection常用API Collection集合API Collection是单列集合的祖宗接口,因此它的功能 ...

  2. 集合框架一:Collection集合

    目录 概述 Colletion接口常用方法 List集合 常用方法 ArrayList实现类 1.底层实现原理 2.常用方法 3.add()方法的扩容问题 4.sort()方法 linkedList实 ...

  3. Java学习之容器上(Collection接口常用方法,Iterator接口,使用foreach循环遍历Collection集合元素,Set集合通用知识(Hashset类,hashcode()与Lin

    1.容器API的类图结构如下: JAVA的集合类是一种特别有用的工具类,它可以用于存储数量不等的多个对象,并可以实现常用数据结构,如栈,队列等,除此之外,JAVA集合还可用于保存具有映射关系的关联数组 ...

  4. collection集合 地址_java.util包下的集合

    Java 集合可分为 Collection 和 Map 两种体系 1.Collection接口:单列数据,定义了存取一组对象的方法的集合 List:元素有序.可重复的集合 Set:元素无序.不可重复的 ...

  5. 集合中的遍历以及删除元素

    package collection;import java.util.ArrayList; import java.util.Collection; import java.util.Iterato ...

  6. linq判断集合中相同元素个数_JavaSe集合的概念以及集合框架介绍

    ###集合 今天任务 1.概念1.1 集合的概念1.2 集合的框架结果介绍1.3 集合和数组的对比 2.Collection接口2.1 Collections中常用的方法 3.泛型3.1 什么是泛型3 ...

  7. Iterator(迭代器)遍历Collection集合元素

    Iterator(迭代器)是一个接口,它的作用就是遍历容器的所有元素,也是 Java 集合框架的成员,但它与 Collection 和 Map 系列的集合不一样,Collection 和 Map 系列 ...

  8. Java基础-Collection集合接口(List及Set)

    Collection集合接口 1.Collection接口的常用方法 2.Collection集合迭代 3.contains方法解析 4.集合中元素的删除 5.List接口的特有方法 6.Set接口 ...

  9. Collection集合框架

    2019独角兽企业重金招聘Python工程师标准>>> 一,Collection集合框架 在实际开发中,将使用的对象存储到特定数据结构的容器中,而JDK提供了这样的容器--集合框架, ...

最新文章

  1. 周志华:严肃的研究者就不该去触碰强人工智能
  2. Permission denied 故障
  3. 基于DataTables实现根据每个用户动态显示隐藏列,可排序
  4. 【Eclipse】eclipse che 协作开发
  5. Linux web服务器初始化设置
  6. 安卓7.0拍照遇到 Uri暴露错误
  7. Servlet_体系结构
  8. python路3--tuple、str
  9. 详谈DHCP SNOOP等多方面的安全设置(2)
  10. 持续20年,一场威胁Linux存亡的诉讼终结束
  11. 中职计算机技术教学计划,中职计算机教学计划
  12. bzoj5108 [CodePlus2017]可做题 位运算dp+离散
  13. Java 线程池 ThreadPoolExecutor源码简析
  14. 细胞自动机,那是什么?
  15. 【支付】中国银联作为收单机构的支付流程分析
  16. 华电研究生学习和工作总结(2021.11.08-2021.11.12)-围城
  17. html5 video断点续播,vue-video-player 断点续播的实现
  18. matlab 不等式组求解例子,matlab求解不等式组
  19. 最简单的P2P加密聊天软件开发准备
  20. 北京住房公积金联名卡查询使用

热门文章

  1. ps cs6 磨皮插件_磨皮就是几秒的事!2020顶级PS一件磨皮插件DR5、Portaiture分享
  2. python爬取图片源码_python抓取百度图片源码
  3. 我用hbuilder怎么用不了jquery_【权益资讯】机房电脑用不了怎么办
  4. 数据中心机房空调系统的这些“套路”你知多少?
  5. 数据传输完整性_生产系统数据完整性事件常见指标(下)
  6. ML之XGBoost:利用XGBoost算法对波士顿数据集回归预测(模型调参【2种方法,ShuffleSplit+GridSearchCV、TimeSeriesSplitGSCV】、模型评估)
  7. Interview:算法岗位面试—10.29下午上海某电子(偏传统ML算法,外企)数据结构算法+晚上国内某保险公司(偏AI算法,世界500强)技术面试之分类算法、回归算法、聚类算法等细节考察
  8. AI英特尔杯公开课:2019.06.27在线直播《研究生人工智能创新大赛—AI赋能,创新引领》课堂笔记和感悟(二)
  9. BlockChain:《2016年中国区块链产业概况》听课笔记
  10. 已解决:Ubuntu16.4和Windows10创建共享文件夹