day17 集合02 集合元素的迭代,并发修改异常,set,map,集合框架工具类 -> java基础大神进阶学习总结之19天(知识点全面覆盖,细节)

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()

猜你喜欢

转载自blog.csdn.net/weixin_41340417/article/details/107889962