2020-06-23
foreach删除元素为什么会报错
Math.max() 返回两个数中大的那个,源码里是一个三元运算符
final:
final修饰的类不能被继承。(Sting就是一个被final修饰的类,我们只能用,不用继承)
final修饰的变量,是一个常量,只能赋值一次。
protected:
可以被子类,同package下类使用,不对外公开的访问修饰符 在非static修饰下,子类不能通过new父类对象直接调用
default(不写修饰符) 在一个包下的能访问
transient :
瞬态 “不可序列化状态”。
密码,银行卡号等敏感信息,为了安全起见,不希望在网络操作(主要涉及到序列化操作,本地序列化缓存也适用)中被传输。这些信息对应的变量就可以被定义为transient类型。换句话说,这个字段的生命周期仅存于调用者的内存中。
List<Integer> arrayList = new ArrayList<Integer>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
arrayList.add(4);
System.out.println(arrayList);
for (Integer ele : arrayList) {
if (ele == 2) {arrayList.remove(ele);}
}
开始分析:
在编译的时候编译器会自动将对for这个关键字的使用转化为对目标的迭代器的使用
for(Iterator<Integer> iterator = list.iterator(); iterator.hasNext(); 没有i++){
Integer ele = iterator.next();
if(ele == 2)
list.remove(ele);
}
modCount:修改次数,被定义在ArrayList的父类AbstractList中 protected transient int modCount = 0
步骤1:.add 时,先判断是否需要扩容,无论是否需要,modCount 都会++
三次add,modCount = 3, size=3;
步骤2:对Iterator进行初始化。返回一个Itr()类的一个实例(Itr是ArrayList的一个成员内部类)
int cursor;
int expectedModCount = modCount;
步骤3:循环条件的判断
public boolean hasNext() {
return cursor != size();
}
步骤4:循环体内的.next
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
public E next() {
checkForComodification();
int i = cursor;
...
...
...
cursor = i + 1;
...
}
步骤5:进行.remove操作
public boolean remove(Object o) {
if (o == null) {
...
fastRemove(index);
...
}
} else {
...
fastRemove(index);
...
}
}
...
}
private void fastRemove(int index) {
modCount++;
System.arraycopy(elementData, index+1, elementData, index, numMoved);
}
步骤6:remove完成后,开始下一次循环,执行 .next 判断
此时:modCount == 4; 而expectedModCount == 3;
抛 java.util.ConcurrentModificationException
特殊情况:
若是在倒数第二个元素进行删除操作时,经过前面的遍历,next()方法将cursor增加至2,只比size=3少1。
在remove()操作时,size-1=2,hasNext()发现cursor=size,程序并没有遍历最后一个元素,程序正常终止。
如果要修改其他位置元素,都会抛异常
正确姿势:
List<String> list = new ArrayList<>();
list.add("e1");
list.add("e2");
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
String str = iterator.next();
if ("e1".equals(str)) {
iterator.remove();
}
}
迭代器的remove方法与集合的remove方法,最大的不同是,迭代器的remove方法中包括对游标和expectedModCount的修正。
如果是多线程情况:
在使用iterator迭代的时候使用synchronized或者Lock进行同步;
使用并发容器CopyOnWriteArrayList代替ArrayList和Vector。