ArrayList类contains方法实现原理

以ArrayList集合示例

思考:contains方法如何执行?

public static void main(String [] args){List<String> list=new ArrayList<String>();	list.add("张三");	System.out.println(list.contains("张三");
}
分析contains底层代码
 public boolean contains(Object o) { //o为传入的参数,此时的o为上转型对象return indexOf(o) >= 0;		//调用下面indexOf(Object o)方法并把参数传入//因为 下面indexOf方法的返回值为int类型  indexOf方法的返回值 大于等于0 便会返回true 否则反之}public int indexOf(Object o) {	//o为此时方法的形参  参数为上面调用方法时传进来的参数return indexOfRange(o, 0, size);	//调用下面indexOfRange(Object o, int start, int end)方法      size是当前调用contains方法集合元素的个数  0是因为 集合的下标是从0开始的  o 是由外面传进来的值}int indexOfRange(Object o, int start, int end) {Object[] es = elementData; //把当前调用contains方法集合里面的每个元素放到这个数组里面if (o == null) {	//判断o是否为null 当前 o 是有外部传进来的值 所以肯定不为nullfor (int i = start; i < end; i++) {if (es[i] == null) {return i;}}} else {  //因为上面o不是null  所以便会走else块for (int i = start; i < end; i++) {	//因为上面使用该方法时传进来值 此时start =0  end 时当前集合元素的个数if (o.equals(es[i])) {	//o代表外面传进来的值 跟es数组中的每一位元素进行equals比较//此时需要注意   此时出现了多态  因为equals 在object中定义了这个方法在编译时会调用Object中的equals的方法//但是 在运行时会 会调用Object类的子类中所重写的equals方法 那么这时 谁调用equals方法 便会进入到当前调用类中并且使用equals方法return i; //如果找到便会返回当前的int类型的下标}}}return -1; //如果if和else 都不满足 便会返回-1}
String类中 equals比较时的代码

因为我们传进来的Object o是String类型的 那么我们此时便会调用String中重写后的equals方法

   public boolean equals(Object anObject) { //注意 注意 注意 重要的事情 说三遍//equals 是上面这个 indexOfRange(Object o, int start, int end)方法中变量o调用的但是  equals方法中的行参是上面这个 indexOfRange(Object o, int start, int end)方法中的es[]数组 ,数组里面又是储存的当前调用contains方法集合里面的每个元素    if (this == anObject) {  //this代表当前 谁调用便会 指向谁 此时this指向调用equals 方法的o   anObject 是equals方法的形参 也就是 es[]数组中的每一个元素,进行==地址比较如果地址相等返回true return true;}if (anObject instanceof String) { //判断equals 方法的形参是否为String类型String aString = (String)anObject;	//如果上面判断成功 便会把equals方法的形参转为String类型 并赋值给aString变量if (!COMPACT_STRINGS || this.coder == aString.coder) {	//COMPACT_STRINGS 是String 类中定义的实参 值为false (|| 短路与 满足一个条件即可) COMPACT_STRINGS取反为true 进入          return StringLatin1.equals(value, aString.value); //// 调用StringLatin1类中的equals方法 里面的两个参数是 你要比较的两个值 并且会把这两个值 拆分为一个一个放入到byte类型的数组中}}return false;}
StringLatin1类中的equals方法
 public static boolean equals(byte[] value, byte[] other) { //里面两个形参 是上面String类中equals 调用该类中equals 方法传入的值if (value.length == other.length) {	//先比较两个数组的长度 如果长度不同 就不会进入 for (int i = 0; i < value.length; i++) {	//循环比较if (value[i] != other[i]) {	//分别比较两个数组中的每一位元素return false;	//只要 有一位不用便会返回false}}return true;	//如果两个数组里面所存储的每一位元素都相同 便会返回true	}return false;	//如果没进if判断 便会直接返回false}
自定义类中的equals方法

此时我们用Student类 来举例

因为 在上面说明过 equals 在Object中 如果 你调用equals 的类 没有重写 equals 便会调用Object 中的 equals 方法 所以 我们此时要在自定义类中重写equals方法

@Overridepublic boolean equals(Object anObject) {	//equals 是上面这个 indexOfRange(Object o, int start, int end)方法中变量o调用的但是  equals方法中的行参是上面这个 indexOfRange(Object o, int start, int end)方法中的es[]数组 ,数组里面又是储存的当前调用contains方法集合里面的每个元素if(anObject instanceof Student) { //此时我们以 Student 来举例    判断equals 方法的形参是否为Student类型Student stu=(Student)anObject;	//如果上面判断成功 便会把equals方法的形参转为Student类型 并赋值给stu变量return this.id.equals(stu.id);	this代表当前 谁调用便会 指向谁 此时this指向调用equals方法的这个自定义类   那么此时我们用这个类中id 跟 传进来的stu变量里的id 进行比较 比较方式 和上面的讲解的一样}    



ArrayList中contains的方法及原理

ArrayList中contains的方法及原理

contains源代码如下:

img

img

img

这里的O代表contains方法中的参数对象,如果数值大于等于0,就会返回true。

O调用什么样的equals方法取决于O是什么类型

contains方法中的参数类型如果是String类型,则调用String对象中的equals方法

contains方法中的参数类型如果是基本数据类型的包装类,则调用包装类中的equals方法

contains方法中的参数类型如果是类部类型,则调用类部类型中的equals方法

String类型:

img

这时的结果输出为true。

1:当执行到list.contains(“李坦克”)时,调用了contains方法,其中张大炮赋值给了O,O即为String类

2:接着在调用indexOf方法,因为O !=null,所以进入else{ }语句中,O去调用String类的equals方法,先比较地址,在比较每一个字符,有一样相同即返回true,与集合中的元素进行比较,一旦找到相同的,则返回此时对应的i。

3:这时跳转回contains方法中,因为此时i>=0,所以返回true。

4:如果O为null,就会执行if语句,接着通过for循环去判断集合中是否有值为null的元素,若有则返回i,即返回true;如果遍历完集合没有找到null这个元素,则会跳出if语句,执行最后一条语句:return -1;,所以最后会返回false。

*自定义类型:*

*未重写equals方法:*

imgimg

这里首先定义一个学生类,这里返回的是false。

1:执行到list.contains(new Student(“20”))时,跳转contains方法,创建一个Student对象20赋值给O,所以O为Student类。

2:接着就是跳转到indexOf方法中,因为O !=null,进入else语句中,O本来是要调用Student中的equals方法的,但是Student类中没有重写equals方法,所以就要去调用Student父类Object类中的equals方法,而Object中的equals方法是比较地址,当我们每创建一个对象,都会new一个新的空间,也就是每一个对象都会有一个新地址,所以O的地址与集合中的每个元素地址都不一样,所有最终会返回false

3:假如O=null跟String类型一样。

重写equal方法:

imgimg

重写的equals方法中,obj就是集合中每个元素,判断传进来的类型是否为Student类创建出来的对象或者是Student的子类,如果是就执行语句,不是返回false;如果是的话,将obj下转为Student类型,这里this.id是指谁调用equals方法就是谁的id,这里t.id是指传进来的obj下转型t的id。

为什么这里重写equals方法后返回的就是true了。

1:当代码执行到list.contains(new Student(“20”))时,跳转contains方法,创建一个新的对象20赋值给O,这时O就是Student类

2:在调用indexOf方法,因为O !=0,所以直接进入else语句中,因为这里我们在Student类中重写了equals方法,所以O去调用Student类中重写后的equals方法,我们定义的equals方法也是先比较地址,在比较字符,所以会返回true,即条件满足进入if语句,执行return i;

3:跳转回contains方法中,此时i>=0;所以最终会返回true。

4:如果这里O还是为null跟String类型一样

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/555909.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql索引结构优缺点_mysql索引优缺点及注意事项

优点有了索引.对于记录数量很多的表,可以提高查询速度.缺点索引是占用空间的.索引会影响update insert delete速度ALERT!!!1 索引要创建在where和join用到的字段上.2 以下操作符号可以应用索引&#xff1a;&#xff0c;>&#xff0c;BETWEEN&#xff0c;IN&#xff0c…

Mybatis源码分析之(五)mapper如何将数据库数据转换成java对象的

本篇对mybatis从取到数据库数据开始到映射成对象并返回的过程进行了详细的分析。 转换ResultSet成java对象 下面的代码是PreparedStatementHandler中的 Overridepublic <E> Cursor<E> queryCursor(Statement statement) throws SQLException {PreparedStatement …

Java Stream Collectors.groupingBy()实现分组(单字段分组,多字段分组)

1 User实体类 public class User {private Long userId;/*** 用户名(登录)*/private String username;/*** 年龄*/private int age;/*** 性别*/private int sex;/*** 密码*/private String password; }2 单字段分组 //根据年龄分组 List<User> userList new ArrayList…

怎么在mysql查询自己建的表格_oracle数据库中怎么查询自己建的表

select * from user_tables where table_nameABC;可以查询出ABC但前提得是知道表名是ABC 可以根据表建时间不同&#xff0c;来将你本人建的表和数据库自动建的表分开&#xff0c;虽然他们都是同一个用户建的。 在user_table表里没有建表时间这一字段&#xff0c;可以用user_obj…

设计模式总结篇(为什么要学习设计模式,学习设计模式的好处)

在学习完设计模式后&#xff0c;LZ想告诉大家&#xff1a; ​ 对于一名工作不久的程序员来说&#xff0c;学习设计模式是非常有必要的&#xff0c;设计模式可以让你知道在某些场景下如何来设计出适合场景的架子&#xff0c;对&#xff0c;因为经验不丰富&#xff0c;大部分程序…

Mybatis源码分析开篇

Mybatis的由来 iBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code&#xff0c;并且改名为MyBatis 。2013年11月迁移到Github。 iBATIS一词来源于“internet”和“abatis”的组合&#xff0c;是一个基于Java的持久层框架…

java数据库配置_java--数据库(文件配置连接,自定义连接池)

import java.util.ResourceBundle;public class Mtest7Demo {//使用properties配置文件完成数据库的连接/** 开发中获得连接的4个参数(驱动,URL,用户名,密码)通常都存在配置文件中&#xff0c;方便后期维护&#xff0c;* 程序如果需要更换数据库&#xff0c;只需要修改配置文件…

Mybatis源码分析之(一)搭建一个mybatis框架(写一个mybatis的Demo)

数据库工作&#xff1a; 首先准备工作&#xff0c;安装mysql&#xff0c;并且新建一张t_demo表 CREATE TABLE t_demo (name varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,id int(11) NOT NULL AUTO_INCREMENT,PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT4 DEFAUL…

后端开发 java_Java后端开发三年,你不得不了解的JVM

JAVA程序员&#xff0c;三年是个坎&#xff0c;如果过了三年你还没有去研究JVM的话&#xff0c;那么你这个程序员只能是板砖的工具了。下面来个JVM的解析可好&#xff1f;JVM是Java Virtual Machine(Java虚拟机)的缩写&#xff0c;也就是指的JVM虚拟机&#xff0c;属于是一种虚…

Mybatis源码分析之(二)根据配置文件创建SqlSessionFactory(Configuration的创建过程)

SqlSessionFactoryBuilder.build创建SqlSessionFactory&#xff08;粗略走一步流程&#xff09; 看完上篇文章后&#xff0c;你对mybatis应该有个大概的了解了&#xff0c;那么我们知道new SqlSessionFactoryBuilder().build是框架的入口&#xff0c;我们到SqlSessionFactoryB…

c++调用python接口作用是_利用Boost::Python实现C++调用python接口

利用Boost::Python实现C调用python接口2019年11月06日阅读数&#xff1a;7这篇文章主要向大家介绍利用Boost::Python实现C调用python接口,主要内容包括基础应用、实用技巧、原理机制等方面&#xff0c;希望对大家有所帮助。Boost.Python能将C的结构体暴露给Python使用。可是在运…

Mybatis源码分析之(三)mapper接口底层原理(为什么不用写方法体就能访问到数据库)

mybatis是怎么拿sqlSession 在 上一篇的时候&#xff0c;我们的SqlSessionFactoryBuilder已经从xml文件中解析出了Configuration并且返回了sessionFactory。 然后我们要从session;中拿到sqlSession public class DefaultSqlSessionFactory implements SqlSessionFactory {pr…

java中的位移_Java中的位移运算

在Java中&#xff0c;位移运算属于基本运算&#xff0c;符号是<>&#xff0c;即向左位移和向右位移。在Java中只有整数才能位移&#xff0c;所以其他的不考虑&#xff0c;位移运算是将整数在内存中表示的二进制进行位移&#xff0c;所以在Java中分为正数和负数的位移。对…

Mybatis源码分析之(四)mapper访问数据库的底层原理(代理方法中具体访问数据库的细节)

从之前的文章&#xff0c;我们知道了其实mapper真正执行的方法就下面的最后两行。&#xff08;以下所有的分析都基于一次mybatis的一次select查询。 MapperProxy类中的invoke函数 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {i…

mysql count distinct case when_统计符合条件的去重过的数量 - - count distinct if case

现有表结构&#xff1a;CREATE TABLE example_dataset (id int(11) unsigned NOT NULL AUTO_INCREMENT,tel bigint(11) DEFAULT NULL,gender varchar(11) DEFAULT NULL,PRIMARY KEY (id)) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8mb4;插入数据INSERT INTO example_da…

Mybatis源码分析之(六)mybatis拦截器(Interceptor)的实现原理

文章目录前言InterceptorChain保存所有的Interceptor创建四大对象都走ConfigurationInterceptorChain增强对象方法Plugin封装动态代理&#xff0c;让你使用Mybatis拦截器更简单Invocation&#xff0c;让我们能在拦截器中使用动态代理类中的invoke方法中的对象调用时序图小结前言…

Mybatis源码分析之(七)Mybatis一级缓存和二级缓存的实现

文章目录一级缓存二级缓存总结对于一名程序员&#xff0c;缓存真的很重要&#xff0c;而且缓存真的是老生常谈的一个话题拉。因为它在我们的开发过程中真的是无处不在。今天LZ带大家来看一下。Mybatis是怎么实现一级缓存和二级缓存的。(自带的缓存机制)一级缓存 存在BaseExecu…

oauth2 java 获取token_OAuth2 Token 一定要放在请求头中吗?

Token 一定要放在请求头中吗&#xff1f; 答案肯定是否定的&#xff0c;本文将从源码的角度来分享一下 spring security oauth2 的解析过程&#xff0c;及其扩展点的应用场景。Token 解析过程说明当我们使用 spring security oauth2 时, 一般情况下需要把认证中心申请的 token …

Map.getOrDefault()方法

default V getOrDefault(Object key, V defaultValue) {V v;return (((v get(key)) ! null) || containsKey(key))? v: defaultValue;}这是源码&#xff0c;意思就是当Map集合中有这个key时&#xff0c;就使用这个key对应的value值&#xff0c;如果没有这个key就使用默认值de…

java开发原则_java开发中,大家处理异常的原则是什么,是如何处理的?

展开全部最熟悉的陌生人&#xff1a;异常异常的类e5a48de588b63231313335323631343130323136353331333361326365型Throwable— Exception—- RuntimeException— Error需要注意的是&#xff0c;RuntimeException及其子类不需要在方法签名中显示注明异常抛出。例如&#xff1a;v…