java基础总结
day17 集合02 集合元素的迭代,并发修改异常,set,map,集合框架工具类
集合元素的迭代(三种方式)
//作业目的:掌握List迭代的三种方式
1. //for循环
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
for (int i = 0; i < list.size() ; i++) {
System.out.println(list.get(i));
}
2. //forEach循环
for (String val: list) {
System.out.println(val);
}
3. //使用迭代器
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
Iterator表示迭代器对象,迭代器中拥有一个指针,默认指向第一个元素之前,
- boolean hasNext():判断指针后是否存在下一个元素
- Object next():获取指针位置下一个元素,获取后指针向后移动一位
注意forEach的底层就是迭代器iterator
并发修改异常
List<String> list = new ArrayList<>();
list.add("西施");
list.add("王昭君");
list.add("貂蝉");
list.add("杨玉环");
System.out.println(list);
for (String ele : list) {
if("王昭君".equals(ele)) {
list.remove(ele);
}
}
System.out.println(list);
此时报错java.util.ConcurrentModificationException,并发修改异常。
造成该错误的原因是,不允许在迭代过程中改变集合的长度(不能删除和增加)。
底层代码
//迭代器里的remove方法
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification(); //------------------------
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount) //------------------
throw new ConcurrentModificationException();
}
//集合里的remove方法
public boolean remove(Object o) {
final Object[] es = elementData;
final int size = this.size;
int i = 0;
found: {
if (o == null) {
for (; i < size; i++)
if (es[i] == null)
break found;
} else {
for (; i < size; i++)
if (o.equals(es[i]))
break found;
}
return false;
}
fastRemove(es, i); //--------------------
return true;
}
private void fastRemove(Object[] es, int i) {
modCount++; //增加---------------------------
final int newSize;
if ((newSize = size - 1) > i)
System.arraycopy(es, i + 1, es, i, newSize - i);
es[size = newSize] = null;
}
所以我们要通过迭代器的remove方法,这样才不会迭代中改变集合的长度
注意:ArrayList底层事Object【】数组的增删改查。。。的封装操作,所以当ArrayList使用remove方法时,其他未被删除的元素会根据情况往前或者往后移动,所以删除一次后,其他元素的索引就改变了。
set
1.HashSet存储原理:
- set是无序的,底层采用哈希表
- 所以当我们添加元素是会先通过hasecode来计算对应的值,
- 不同则存储搭配指定位置,相同则通过equals方法来判定,如果为true表示同一个元素
- 如果false则表示不同的值有相同的hasecode值,则建立一个链表将元素放在一个位置上。
2.当我们添加对象时,每个对象的每个字段都相同,会根据地址来来生成hasecode值,所以当我们想不添加相同对象时,我们可以重写euqal和hasecode方法,通过根据对象的某些字段来判断是否为同一个对象。
TreeSet
- TreeSet类底层才有红黑树算法,会对存储的元素对象默认使用自然排序(从小到大)。
- 当然这个默认排序是实现了Comparable接口的包装类等等,包装类会拆箱为基本数据类型
当我们自己定义的对象时,是没有排序的
排序的两种方式
- 第一种:对象实现Comparable接口 ,覆盖compareTo方法
- 第二种:是写一个比较器类实现Comparable接口,然后再将该类传入treeset集合中
覆盖compareTo方法比较规则,拿当前元素和另一个元素做比较:
this > o:返回正整数 1 ,优先级较高 加入该节点的左边节点
this < o:返回负整数 -1 ,优先级较低 加入该节点的右边节点
this == o: 返回 0 ,此时认为两个对象为同一个对象。
map
注意当存储相同的键时,会覆盖
map三个获取:
//获取所有的键 set无序
Set<Object> objects = hashMap.keySet();
//获取所有的值 有序
Collection<Object> values = hashMap.values();
//通过获取所有键值对来获取键值
Set<Map.Entry<Object, Object>> entries = hashMap.entrySet();
集合框架的工具类
集合框架中有很多工具类可以通过api查看,比如Array.toString() ,Array.asList()