这个bug是在学习Collection集合当中的ArrayList集合时,在关于remove方法时候,遇到的一个问题,记录一下下~
首先,贴一下报错的源代码:
package day14;
import java.util.ArrayList;
import java.util.Collection;
public class Test3_Collection {
public static void main(String[] args) {
// Collection collection = new Collection<>();
//Collection是接口不能直接实例化
ArrayList<Integer> c = new ArrayList<>();
c.add(100);
c.add(200);
c.add(300);
c.add(400);
c.add(500);
System.out.println(c);
// c.clear();清除c中所有元素
// System.out.println(c);
System.out.println(c.contains(100));
System.out.println(c.isEmpty());
System.out.println(c.remove(200));
System.out.println(c);
}
}
在控制台打印的结果如下:
错误提示:IndexOutOfBoundsException
错误原因:在上面代码中想要移去这个"200"这个元素,但是,remove方法是用的下标法来查找内容的,所以数组越界现象发生
再来看另一个测试的小版本:
package day14;
import java.util.ArrayList;
import java.util.Collection;
public class Test3_Collection {
public static void main(String[] args) {
// Collection collection = new Collection<>();
//Collection是接口不能直接实例化
ArrayList<Integer> c = new ArrayList<>();
c.add(100);
c.add(200);
c.add(300);
c.add(400);
c.add(500);
System.out.println(c);
// c.clear();清除c中所有元素
// System.out.println(c);
System.out.println(c.contains(100));
System.out.println(c.isEmpty());
System.out.println(c.remove("200"));
System.out.println(c);
}
}
这里面运行结果图片贴一下,如下图:
程序运行到时没有报错,但是显然没有实现想要把“200”这个元素移除的目的,在回到代码中看一下编译器给的提示是什么,为什么会出现这种情况呢?
这里提示写到:‘ArrayList’ may not contain objects of type ‘String’
很明显:我们创建的这个集合是用来装Integer类型的,现在放了一个“String”类型的元素进去,编译器翻译不了这个内容,所以remove这个方法执行的结果就是false,我们再点击进去后面的三个小点点看一下提示:
‘ArrayList’ may not contain objects of type ‘String’
Inspection info: Reports method calls to parameterized collections, where actual argument type does not correspond to the collection’s elements type. For example if you have the following code:
//检查信息:提示下集合的方法调用,其中实际参数类型必须要对应于集合的元素类型。例如,如果你有以下代码:
List list = getListOfElements();
list.remove("");
- the call to remove() will be highlighted. The option ‘Report suspicious but possibly correct method calls’ makes it possible to ignore potentially correct code, like this:
Number number = new Integer(0);
list.remove(number));
根据上面的提示:明确告诉一个信息:remove()的调用将突出显示。“报告可疑但可能正确的方法调用”选项可以忽略可能正确的代码。在调用remove这个方法的时候,执行的操作实际是按照下标来进行操作的,而不是按照这个里面的number俩进行操作的。
根据提示我来修改一下做法:
`package day14;
import java.util.ArrayList;
import java.util.Collection;
public class Test3_Collection {
public static void main(String[] args) {
// Collection collection = new Collection<>();
//Collection是接口不能直接实例化
ArrayList<Integer> c = new ArrayList<>();
c.add(100);
c.add(200);
c.add(300);
c.add(400);
c.add(500);
System.out.println(c);
// c.clear();清除c中所有元素
// System.out.println(c);
System.out.println(c.contains(100));
System.out.println(c.isEmpty());
System.out.println(c.remove(1));
System.out.println(c);
}
}
`
运行结果如下图
这里面在remove()方法上面按住ctrl进去看一下它里面的源码的代码是怎么写的:
public boolean remove(Object o) {
if (o == null) {//如果要移除的元素为null
for (int index = 0; index < size; index++)//从0开始循环,每次往后+1,循环到小于目标对象的长度时停止
if (elementData[index] == null) {//如果元素中下标==null
fastRemove(index);//快速移除这个元素
return true;//返回true
}
} else {//如果要移除的元素不为null
for (int index = 0; index < size; index++)//从0开始循环,每次往后+1,循环到小于目标对象的长度时停止
if (o.equals(elementData[index])) {//对象等于元素下标值对应的数据
fastRemove(index);//快速移除这个元素
return true;//返回true
}
}
return false;//如果要移除的元素不为null,且没有找到这个对象等于元素下标值对应的数据
}
所以就非常清楚了,源码当中的判断逻辑分了3步走:
- 先判断,要移除的这个元素是不是null,如果是null,按照下标寻找对应元素,并快速移除,返回true;
- 再根据上一步,要移除的这个元素不是null,按照下标寻找对应元素,并快速移除,返回true;
- 再根据上两步,要移除的这个元素不是null,且没有找到这个对象等于元素下标值对应的数据,返回false。