成员变量:类内方法外的变量
局部变量:方法中的变量
区别 | 成员变量 | 局部变量 |
---|---|---|
编写位置不同 | 类内方法外 | 方法内或方法声明上 |
内存位置不同 | 堆内存 | 栈内存 |
生命周期不同 | 随着对象的存在而存在,随着对象的消失而消失 | 随着方法的调用而存在,随着方法的调用完毕而消失 |
初始化值不同 | 有默认的初始值 | 没有默认的初始值,必须先定义,赋值,才能使用 |
理解:
①类中位置不同。
局部变量在方法内或方法申明上,方法申明上指的是:定义方法时形参的位置,也就是括号中的变量。
// 29-ListDemo3
public class ListDemo3 {
//需求:
/*
有一个集合,
添加三个元素 hello、world、java,
遍历集合,得到每一个元素,看有没有world这个元素,如果有则添加元素javaee
* */
public static void main(String[] args){
List<String> list = new ArrayList<String>(); 分析步骤1
String s1 = "hello";
String s2 = "world";
String s3 = "java";
list.add(s1);
list.add(s2);
list.add(s3);
//采用for循环的形式遍历集合元素不报错
/* for (int i = 0 ; i <list.size() ; i++){
String s = list.get(i);
if(s.equals("world")){
list.add("javaee");
}
}*/
//采用迭代器的形式
Iterator<String> it = list.iterator(); 分析步骤1
while (it.hasNext()) {
String s = it.next();
if(s.equals("world")){
list.add("javaee"); 分析步骤1
}
}
// 使用迭代器遍历集合元素会报错:ConcurrentModificationException
System.out.println(list);
}
}
原因分析:采用迭代器出现异常
主要:采用迭代器的形式,对集合进行add添加元素操作之后,modCount变量的数值会增加,exceptedModCount变量不变,集合对象.next方法获取集合变量的时候会执行checkForComodification()方法,比较modCount和exceptedModCount的数值,不相等会报ConcurrentModificationException异常。
1 首先是List接口,接着使用接口中定义的两个方法:iterator、add
public interface List<E> {
Iterator<E> iterator();
boolean add(E e);
}
2 最终创建对象,new的是ArrayList这个实现类的对象
public abstract class AbstractList<E>{
protected transient int modCount = 0;
此变量在AbstractList<E>类中
}
public class ArrayList<E> extends AbstractList<E> implements List<E> {
ArrayList实现了List这个接口,就需要重写List中的方法,例如:iterator、add
public boolean add(E e) {
ensureCapacityInternal(size + 1); //自己测试显示内容
elementData[size++] = e;
return true;
//视频显示内容
modCount++;
add(e,elementData,size);
return true;
}
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int expectedModCount = modCount;
/*
expectedModCound:预期修改集合的次数
modCount:实际修改集合的次数
最开始执行时,两者数量相同
变量modCount来自AbstractList<E>中,且用protected修饰,则子类可以直接访问到父类的成员变量,所以最开始两个变量的值都是0
*/
/*
在实际代码运行中,
if(s.equals("world")){
list.add("javaee"); 分析步骤1
}
上述代码一旦条件满足,就会执行集合添加元素的操作,
按照视频内容理解:每执行一次add方法,modCount会自加一,但是expectedModCount变量不变,接着执行next方法就会执行checkForComodification方法判断两者不相同时就会抛出异常。
*/
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
final void checkForComodification() {
if (modCount != expectedModCount)
// 此处出现问题的原因是 modCount = 修改集合的次数、expectedModCount = 预期修改集合的次数
throw new ConcurrentModificationException();
}
}
}
3 分析 抛出异常的原因是it.next()方法执行,又调取checkForComodification()方法出现问题。
原因分析:采用for循环遍历集合元素不报错分析
使用for循环遍历,获取元素使用的是集合对象.get方法。
public class ArrayList<E> extends AbstractList<E> implements List<E> {
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
调用get方法并没有对modCount、exceptedModCount变量进行比较,即使更改了modCount变量的值,但是也不影响执行。
}
关于视频和自己练习中add方法不相同问题理解:
public class ArrayList<E> extends AbstractList<E> implements List<E> {
// ArrayList实现了List这个接口,就需要重写List中的方法,例如:iterator、add
//自己测试显示内容
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
分析是否相同:主要通过追述方法具体实现
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
别的没有看懂,但是有关于变量modCount的++
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
//视频显示内容
public boolean add(E e) {
modCount++;
add(e,elementData,size);
return true;
}
并发修改异常解决及分析总结
并发修改异常:ConcurrentModificationException
产生原因:迭代器遍历的过程中,通过集合对象修改集合中的元素,比如添加元素(对象.add),造成了迭代器获取元素中判断预期修改值和实际修改值不一致
解决方法:用for循环遍历,然后用集合对象做对应的操作(对象.get)