原创

Java集合-List


List

List本身也是一个接口,是一个元素存入和取出有顺序的,且元素可以重复的一个集合接口。

此接口的用户可以对列表中每个元素的插入位置进行精确地控制,用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。

List的特有功能:

  • 增加: void add(int index, Object element):根据指定索引位置插入元素 boolean addAll(int index, Collection c):根据指定索引位置,插入整个集合(这里的索引不是指元素,而是一个Collection的位置)
  • 删除: Object remove(int index):根据指定索引位置删除某一个元素
  • 修改: Object set(int index, E element):根据指定索引位置,修改元素内容
  • 查询: Object get(int index):根据索引位置,获得指定元素 int indexOf(Object o):查找指定元素第一次出现的索引位置,如果不存在则返回-1 int lastIndexOf(Object o):查找指定元素最后一次出现的索引位置,如果不存在则返回-1 List subList(int fromIndex, int toIndex):此指定索引位置开始,到指定索引位置结束,截取元素,返回一个新的list集合

List集合的新的遍历方式:

方式一:通过循环+get来配合遍历

            for (int i = 0; i < list.size(); i++) {
                System.out.println(list.get(i));
            }

方式二:使用listIterator()迭代遍历 ListIterator: 允许程序员按任一方向遍历列表、迭代期间修改列表,并获得迭代器在列表中的当前位置。 boolean hasNext():判断是否存在下一个元素 Object next():返回集合的下一个元素 boolean hasPrevious():判断是否存在上一个元素 Object previous():返回集合的上一个元素

List的子类:

    ArrayList:底层维护的是一个Object数组,特点:查询速度快,增删比较慢
    LinkedList:底层维护的是一个链表,特点:查询速度比较慢,增删速度快
    Vector:一个非常古老的集合,JDK1.O版本就诞生看,大部分功能和ArrayList是一致的,区别是这玩意是线程安全的。
           但是因为结构的问题,他的处理效率要远远低于ArrayList,一般尽量避免使用,因为即使要线程安全,我们在多线程的时候可以解决这个问题。

数组的弊端

  1. 数组的长度一旦被初始化,就不可变,不利于扩展
  2. 数组存储的数据类型只能是同一数据类型
  3. 数组可以存储基本数据类型,基本数据类型其实违反了万物皆对象的思想。
  4. 数组的功能比较单一,不利于添加、删除、插入等相关操作,而且效率比较低
  5. 数组存储的数据是必须有序(插入和取出是有序)的,而且可以进行重复。

集合的优点

  1. 集合不存在长度概念,新的数据进来自动扩增,数据离开自动缩减(弹性伸缩)
  2. 只能存储引用数据类型(完全符合面向对象思想)
  3. 功能丰富,提供了增删改查的所有相关功能
  4. 子类众多,可以根据不同要求,通过多态的方式 选择不同的子类实现

集合遍历 方式一:将集合转换成Object数组,然后数组进行遍历

Object [] obj = con.toArray();
for (int i = 0; i < obj.length; i++) {
   String s = (String)obj;
   System.out.println(s);
}

方式二:使用jdk5的foreach循环

for(Object str: con){
   String s = (String) str;
   System.out.println(s);
}

导语:底层其实还是采用的迭代器,无需转换数组,无需确定索引。 方式三:使用Iterator

Iterator it = con.iterator();
while (it.hasNext()){
   System.out.println(it.next());
}

Iterator被称之为迭代器(设计模式一种),主要的作用是用于遍历Collection集合当中的元素

Collection其实已经继承Iterable的接口,而Iterable有有一个Iterator的方法,这个方法又实现了Iterator的接口。

Iterator的方法: boolean hasNext() 判断集合当中是否存在下一个元素 Object next() 获取下一个元素的内容 void remove() 移除迭代最后一个元素

ArrayList

ArrayList类的属性:

  1. 对象数组:ArrayList的底层数据结构

private transient Object[] elementData;

  1. elementData中已存放的元素的个数,注意:不是elementData的容量

private int size;

(1)ConcurrentModificationException

当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。
ArrayList本身其实也是采用快速失败机制进行处理,通过一个modCount这个参数来进行实现,Iterator本身和ArrayList是没有直接关联的。
但是有一种情况可能会出现并发现象(同一个时间点同时执行了某一件事),当iterator已经在hasNext的时候就已经判断了不存在下一个元素,而ArrayList.add()又恰好在这同一时刻又新添加了元素,所以可能造成数据错乱,JDK本身就考虑好了这件事,他使用了一个计数器modCount。
迭代器的执行和add()的执行其实都有共同去维护一个计数的过程,只要在计数过程当中,计数被修改了即迭代器立马失败,而不是冒着危险在将来一个不确定的时候再去产生异常。

解决方式:

1.使用迭代器的添加跟删除

2.不使用迭代器

(2)ArrayList在jdk7和jdk8的一些区别

ArrayList是List的可变数组的实现方式 .

Jdk7:

类似饿汉式、在创建对象,使用无参构造的时候,其实就创建了一个长度为10的一个数组进行维护

JDK8:

类似懒汉式、在创建对象,使用无参构造的时候,并没有给数组指定任何的长度,而是在第一个元素添加的时候才会去生成一个 10个长度的数组

/**
* 创建一个容量为initialCapacity的空的(size==0)对象数组
*/
public ArrayList(int initialCapacity) {
    super();//即父类protected AbstractList() {}
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity:" + initialCapacity);
        this.elementData = new Object[initialCapacity];
}
/** * 默认初始化一个容量为10的对象数组 */
public ArrayList() {
this(10);//即上边的public ArrayList(int initialCapacity){}构造器
}

LinkedList

是List子类当中,采用双向链表的一种实现方式的子类,内部不存在任何数组的声明,而是定义了链表的开端和结尾。

特有成员方法

    void addFirst(E e):将元素添加到集合首位
    void addLast(E e)  将元素添加到集合结尾:
    E getFirst() 获取第一个元素
    E getLast(E e)  获取最后一个元素
    E removeFirst() 删除第一个元素
    E removeLast() 删除最后一个元素

1.栈(存储方式的先进的后出)

    void push(E e):依照栈结构的方式进行数据插入(压栈)
    E pop()  依照栈结构的方式将数据取出(弹栈)

2.对列(先进的先出)

    boolean        offer(E e): 依照队列结构的方式将数据进行插入(因为对列是需要进行排队是,所有永远最后一个)
    E poll() 依照队列的结构取出首位数据,并且删除

ArrayList/LinkedList/Vector的区别

ArrayList/LinkedList本质上两者都是线程不安全的,相比线程安全的Vector来说,效率要比较快。

另外ArrayList底层维护的是一个动态数组的数据结构,而LinkedList基于一个双向链表的一个数据结构。

对于随机访问get/set,ArrayList绝对优于LinkedList,因为LinkedList要不断的移动指针。

对于新增(add)和删除(remove)数据来说,LinkedList比较有优势,因为ArrayList不断创建新的集合进行拷贝和运算。

Vector和ArrayList几乎一致,唯一的区别就是Vector是一个强同步类(synchronized) ,内存开销特别大,访问特别慢。

正常情况下ArrayList是完全可以取代Vector,因为我们自己可以手动控制任何对象是否同步。

List子类的使用依据

Vecter

Vecter较Array安全(原因:Vecter只允许在同一时间段运行一个线程)

Vecter在查询和增删方面的效率都不高

其余特点与ArrayList相似

ArrayList

因为ArrayList底层维护的是数组,所以在查询方面ArrayList的效率比较高

LinkedList

因为LinkedList底层维护的是链表,所以在增删方面LinkedList的效率比较高

java
  • 作者:陌攻(联系作者)
  • 发表时间:2023-02-10 08:13
  • 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
  • 公众号转载:请在文末添加作者公众号二维码
  • 评论