ArrayList类contains方法实现原理

x33g5p2x  于2022-01-11 转载在 Java  
字(4.3k)|赞(0)|评价(0)|浏览(337)

以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 是有外部传进来的值 所以肯定不为null
            for (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方法

@Override
	 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(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源代码如下:

**

**

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

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

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

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

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

String类型:

这时的结果输出为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方法:

这里首先定义一个学生类,这里返回的是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方法:

重写的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类型一样

相关文章