深度解析Contains底层代码
在分析contains之前,我们先看一下==和equals区别,
1、==和equals区别
String str1="Jim"; String str2 ="Jim"; System.out.println(str1==str2);
==:基本数据类型比较值是否相同;引用类型比较地址是否相同
String str3="Jim"; String str4 =new String("Jim"); System.out.println(str3.equals(str4));
equals:Object类中equals实质就是比较地址是否相同;一些数据类型在引用上重写了equals(),String类中equals实质是比较字符转内容后是否相同。
2.contains底层源码分析
1>先上一段代码来调用contains。
List<String> name= new ArrayList<>(); name.add("Jimmy"); System.out.println(name.contains("Tonny"));
2>按着键盘Ctrl+鼠标左键单击进入ArrayList数组里的contains方法。这是我们会看到如下内容,其object里面的参数o为我们要比较的对象Tonny,对Tonny进行了上转型操作,返回值为判断indexof(Tonny) >= 0。
public boolean contains(Object o) {//Tonny为传入参数,o指向Tonny对象,Tonny为上转型对象 return indexOf(o) >= 0;//调用下面的indexOf方法 }
3>接着Ctel+左键点击indexof,进入indexof方法,该方法并未做什么操作,只是将参数封装调入到另一个方法indexOfRange取进行字符串截取比较。点击进去indexOfRange。
public int indexOf(Object o) { return indexOfRange(o, 0, size); }
4>关键点:字符串比较。
int indexOfRange(Object o, int start, int end) { //Tonny为传入参数,start为该数组的0位,end为末尾。 Object[] es = elementData;//将要进行判断的数组列表 if (o == null) {//Tonny地址不为空,不执行if语句 for (int i = start; i < end; i++) { if (es[i] == null) { return i; } } } else {//遍历集合中所有元素判断是否存在元素与test相同 for (int i = start; i < end; i++) { if (o.equals(es[i])) {//使用equals方法判断是否相等 return i;相等,则返回该值所在位置坐标,上面contains方法最终返回true。 } } } return -1;//不相等,则返回-1值上面contains方法最终返回false。 }
3、contains代码实用场景
1。String类型比较
两者参数相同,类型相同,最后返回值为true。如果类型不同||参数不同则返回结果为false。
List<String> names= new ArrayList<>(); names.add("Jimmy"); String name="Jimmy" System.out.println(names.contains("Jimmy"));
int indexOfRange(Object o, int start, int end) { //name为传入参数,o指向name对象,name为上转型对象 Object[] es = elementData; if (o == null) {/name指向的字符串不为null,if语句不执行 for (int i = start; i < end; i++) { if (es[i] == null) { return i; } } } else { for (int i = start; i < end; i++) {//for遍历该数组获取其下标 if (o.equals(es[i])) { //拿Jimmy对象和各个元素进行比较判断,这是我们会发现两者字符相同 return i;//返回其相等后的坐标值给上面的contains方法,最后返回true。 } } } return -1; }
2。判断自定义类型
接下来我们创建Student类型对象,向ArrayList数组添加元素。这里就会发现结果为false,两者值虽然相同,但两者都是创建的新的对象,两者的内存地址不相等,自定义类型在比较时用的是Object的equals方法(比较地址是否相同),所以返回为false。
List<Student> list = new ArrayList<>(); list.add(new Student("Tom")); String student= new Student("Tom"); System.out.println(list.equals(student)));
int indexOfRange(Object o, int start, int end) { Object[] es = elementData; if (o == null) { for (int i = start; i < end; i++) { if (es[i] == null) { return i; } } } else { for (int i = start; i < end; i++) { if (o.equals(es[i])) { //在这里比较时equals用的是Object的equals方法(比较地址是否相同) return i; } } } return -1;//所以两者地址不相同,返回-1值上面contains方法最终返回false。 }
3。重写equals方法
通过上述自定义类型很难满足我们的需求,当两者内容相同,数据类型相同时我们想让他们相等,这里我们就要对Object里的equals方法进行重写操作。
@Override public boolean equals(Object obj) { if (obj instanceof Student) { Student other = (Student) obj; return Objects.equals(this.name, other.name); } return false; }