本文介绍: HashMap在Map.Entry静态内部实现存储键值对,HashMap使用哈希算法,在putget方法中,使用hashCodeequals方法使用put方法时,使用keyhashcode哈希算法来找出存储键值对的索引,Entry存储在LinkedList中,如果存在entry,使用equals检查传递key是否存在,如果存在,会覆盖value,如果不存在,会创建一个新的entry然后保存元素必须定义hashCode()和equals()方法,遍历元素时,会按照添加的进去的顺序

时候需要存储一组数据,之前使用数组,但是数组具有固定的容量,但是在写程序时并不知道需要多少对象,在java.util包下提供了一套完整集合类,包含List、Set、Queue、Mapjava集合类都可以自动地调整自己大小

创建集合时,经常使用泛型,可以在编译期防止将错误类型放入到集合中。

集合概念

集合分为两个基本接口

List

存储有序,可以重复元素,相当于动态数组 集合中元素所在类要重写equals方法

两种类型list

List特性

ArrayList和Vector的异同

相同

不同

  • Vector是同步的,ArrayList不是,但是已过时,使用CopyOnWriteArrayList
  • ArrayList比Vector快

LinkedList链表

LinkedList添加了一些方法,使其可以被用作栈,队列双向队列,方法差异

ArrayList和LinkedList的区别

迭代器Iterators

Iterator

Iterator接口提供了遍历任何Collection接口,取代了java集合框架中的Enumeration,迭代器允许调用者迭代过程移除数据

iterator只能单向移动

Enumeration和iterator的区别

ListIterator

堆栈stack

堆栈是后进先出(LIFO),最后压入(push)栈的元素,第一个弹出(pop)栈。

java1.0中有一个stack类,但是设计的不好,Java6添加了ArrayDeque,其中包含直接实现堆栈功能的方法

Set

Set不保存重复的元素。查找是Set最重要的操作选择HashSet实现针对快速查找进行了优化

存储无序不可重复 添加Set集合中的元素所在类要重写equalshashCode方法

无序性:指的是元素在底层存储的位置无序

Map

键值 key不可重复,一个keyvalue组成一个entry

map分类

HashMap专为快速访问而设计,TreeMap保持键始终处于排序状态没有HashMap快。LinkedHashMap按插入顺序保存其元素,但使用散列提供快速访问的能力

HashMap工作情况

HashMap在Map.Entry静态内部类实现存储键值对,HashMap使用哈希算法,在putget方法中,使用hashCode和equals方法,使用put方法时,使用keyhashcode哈希算法来找出存储键值对的索引,Entry存储在LinkedList中,如果存在entry,使用equals检查传递的key是否存在,如果存在,会覆盖value,如果不存在,会创建一个新的entry然后保存get的时候也是先通过hashcode找到数组中的索引,然后使用equals找到正确的Entry,在进行取值

HashMap默认初始容量是32,负载因子是0.75,阈值是容量乘以负载因子,当map大小阈值大时,HashMap会对map的内容进行重新哈希

HashMap和HashTable的区别

  • HashMap允许key和value为null,HashTable不允许
  • HashTable是同步的,HashMap不是
  • HashMap可以转为LinkedHashMap,使得遍历有序,HashTable的顺序无法预知
  • HashMap提供对key的set进行遍历,所以是fail-fast的,HashTable提供对key的Enumeration进行遍历,不支持fail-fast
  • HashTable应该被CocurrentHashMap替代

队列

队列操作

队列是一个先进先出(FIFO)集合,LinkedList实现了Queue接口,并且提供了一些方法支持队列行为

PriorityQueue优先级队列

优先级队列声明下一个弹出的元素是最需要的元素。

BlockingQueue队列

concurrent包下的类,在进行检索移除一个元素的时候,会等待队列变成非空;当添加一个元素的时候,会等待列中的可用空间。主要用于实现生产者消费者模式

Collections工具

unmodifiableCollection方法

Collections.unmodifiableCollection(list);Collections.unmodifiableList(list);使用该方法会创建一个只读集合,所有改变集合的操作都会抛出UnsupportedOperationException

public static <T&gt; Collection<T&gt; unmodifiableCollection(Collection<? extends T&gt; c) {
        return new UnmodifiableCollection<>(c);
}

synchronizedCollection方法

Collections.synchronizedCollection(list)方法可以创建一个线程安全的集合

public static <T> Collection<T> synchronizedCollection(Collection<T> c) {
    return new SynchronizedCollection<>(c);
}

问题

1、遍历时移除List中的元素

使用forEach和Iterator

在使用forEach遍历时,实际上是使用的Iterator,使用的核心方法是hasNext()和next(),但是使用的是list.remove,来看个例子

//源码
public class TestList {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("J");
        list.add("A");
        list.add("V");
        list.add("A");
        for (String s: list) {
            list.remove(s);
        }
    }
}

//编译之后
public class TestList {
    public TestList() {
    }

    public static void main(String[] args) {
        List<String> list = new ArrayList();
        list.add("J");
        list.add("A");
        list.add("V");
        list.add("A");
        Iterator var2 = list.iterator();
        while(var2.hasNext()) {
            String s = (String)var2.next();
            list.remove(s);
        }
    }
}  

之前说过,Iterator在遍历时,不允许其他线程对该集合进行操作,看一下ArrayList的iterator是怎么实现的

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)
        throw new ConcurrentModificationException();
}

在每次获取下一个元素时,都会比较modCount 和 expectedModCount

然后在调用的list的remove方法会导致modCount增加(modCount表示修改次数

public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1elementData, index,
                             numMoved);
        elementData[--size] = null// clear to let GC do its work

        return oldValue;
    }

此时iterator的next方法中两个变量就不一致了,就会抛出ConcurrentModificationException异常

再看一下如果使用iterator的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();
    }
}

iterator在remove之后会将modCount的值赋给expectedModCount,就不会出现两个变量不等的情况了

不使用forEach遍历

使用普通for循环,有两种方式,第一种是使用正序遍历,但是进行remove操作之后要把遍历的索引进行修正减一,否则在移除下一个的时候就会出错,第二种就是使用倒序遍历

// 正序遍历
for (int i = 0; i < list.size(); i++) {
    String s = list.remove(i);
    i = i - 1;
    System.out.println(s);
}

//倒序遍历
for (int i = list.size() - 1; i >= 0; i--) {
    String s = list.remove(i);
    System.out.println(s);
}

2、fail-fastfail-safe

java.util包中集合类被设计fail-fast的,而java.util.concurrent中集合为fail-safe的。fail-fast迭代器抛出ConcurrentModificationException,而fail-safe迭代器从不抛出ConcurrentModificationException,Iterator的安全失败是基于对底层集合做拷贝,不受源集合上修改影响

fail-fast

fail-fast迭代器抛出ConcurrentModificationException,通过modCount来进行实现,在进行迭代时,每次对于元素的修改都会修改该值,一旦该值被修改了,就会抛出异常

// 当Itr被实例化的时候,记录一下迭代器被实例化时ArrayList的修改次数(在用ArrayList进行add/remove操作时modCount每次都加一)
int expectedModCount = modCount;

// 检查是否被修改了
    final void checkForComodification() {
          // 当修改次数与Itr被实例化时的修改次数不一致时,说明在进行迭代操作的时候其他线程进行了ArrrayList的add/remove操作,此时抛出ConcurrentModificationException,即为fast-fail快速失败机制
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }

3、Arrays.asList

这个方法返回的是一个ArrayList,不过这个ArrayList是Arrays类的内部类,在调用add方法的时候会直接报错

UnsupportedOperationException这是运行异常

public void add(int index, E element) {
    throw new UnsupportedOperationException();
}

https://zhhll.icu/2020/java基础/集合/1.java基础之集合/

本文 mdnice 平台发布

原文地址:https://blog.csdn.net/Lxn2zh/article/details/134660604

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_39624.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除!

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注