Java集合List的总结。

Java集合List的总结。
java集合框架图。在这里插入图片描述
常用的集合有ArrayList,LinkedList,它们继承于List接口;List接口继承于Collection。

关于ArrayList

ArrayList底层基于数组实现,数组在内存中是连续分配的地址空间。
区别:ArrayList的优势是对数组的升级,ArrayList是一个动态的数组,提供了一些方法,比如增删改查,直接操作。
数组在内存中地址空间是固定的,插入删除元素时,需要扩容缩容操作,效率没有使用ArrayList高;然而数组利用下标索引查找元素时效率更高,ArrayList需要从头到尾进行遍历。

自定义ArrayList

提供了add(E value)/remove(E value)/set(index,value)/get(index)/contains(value)/size()/isEmpty()

import java.util.Arrays;

public class MyArrayList<E> {
    
    
    private E  elements[];
    private int size;
    private static final int defaultcapacity=5;//默认的初始化参数

    public MyArrayList(int capacity) {
    
    
        elements = (E[])new Object[capacity];
    }
    public MyArrayList(){
    
    
        this(defaultcapacity);
    }
    public void add(E value){
    
    
        //是否需要扩容
        if (size==elements.length){
    
    
               elements=Arrays.copyOf(elements,elements.length*2);//二倍扩容
        }else {
    
    
            elements[size++]=value;
        }
    }
    public boolean remove(E value){
    
    
        if (size==0){
    
    
            return false;
        }else {
    
    
            for (int i=0;i<size;i++){
    
    
                if (elements[i]==value){
    
    
                    System.arraycopy(elements,i+1,elements,i,size-1-i);
                    elements[--size]=null;
                    return true;
                }


            }
        }
               return false;
    }
    public void checkIndex(int index){
    
    
        if (index<0||index>elements.length){
    
    
            throw new UnsupportedOperationException("下标违法");
        }


    }
    public boolean set(int index,E value){
    
    
           try{
    
    
               checkIndex(index);
               elements[index] = value;
               return true;

           }catch (UnsupportedOperationException  e){
    
    
               System.out.println(e.getMessage());
               return false;
           }
}
    public E get(int index){
    
    
        try{
    
    
            checkIndex(index);
            return elements[index];
         }catch (UnsupportedOperationException e){
    
    
            System.out.println(e.getMessage());
            return  null;
        }

    }

     public boolean contain(E value){
    
    
        if (size==0){
    
    
            return false;
        }
        for (int i=0;i<size;i++){
    
    
            if (elements[i].equals(value)){
    
    
                return true;
            }
        }
        return false;

     }
     public int size(){
    
    
        return this.size;
     }
     public boolean isEmpty(){
    
    
        return this.size==0;
     }
     public String toString(){
    
    
        StringBuilder strs = new StringBuilder();
        for (int i=0;i<size;i++){
    
    
            strs.append(elements[i]+" ");
        }
        return strs.toString();

     }


}

ArrayList源码

扩容方式

private void grow(int minCapacity) {
    
    
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
     private static int hugeCapacity(int minCapacity) {
    
    
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

增删改查操作

 public boolean contains(Object o) {
    
    
        return indexOf(o) >= 0;
    }
      public int indexOf(Object o) {
    
    
        if (o == null) {
    
    
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
    
    
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
    //尾部添加元素
    public boolean add(E e) {
    
    
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
    //中间添加元素
     public void add(int index, E element) {
    
    
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }
    //有返回值的删除
     public E remove(int index) {
    
    
        rangeCheck(index);

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

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

        return oldValue;
    }
    //无返回值的删除
      public boolean remove(Object o) {
    
    
        if (o == null) {
    
    
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
    
    
                    fastRemove(index);
                    return true;
                }
        } else {
    
    
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
    
    
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
      private void fastRemove(int index) {
    
    
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }

ArrayList中迭代器的实现

自定义迭代器

class MyIterator<E> implements Iterable{
    
    
    private E[] elements;//存放元素的容器
    private int size; //存放元素的个数

    public MyIterator(E[] elements){
    
    
        this.elements = elements;
        this.size = elements.length;
    }
    @Override
    public Iterator iterator() {
    
    
        return new Iterator() {
    
    
            @Override
            public boolean hasNext() {
    
    
                return false;
            }

            @Override
            public Object next() {
    
    
                return null;
            }
        };
    }
}

迭代器源码
源码中有modCount,定义于AbstractList,存储结构的修改次数
fast-fail机制:使用迭代器遍历时,如果调用集合add/remove方法修改集合的结构,则会抛出ConcurrentModificationException异常;

   private class Itr implements Iterator<E> {
    
    
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        Itr() {
    
    }

        public boolean hasNext() {
    
    
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        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];
        }

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

CopyOnWriteArrayList实现了non-fast-fail机制
non-fast-fail:复制集合,对集合结构性操作都建立在副本之上,迭代器迭代的是原先的集合,迭代器遍历读取到的数据并不是最新的数据,以copyonwriteArrayList中的add源码为例:

public boolean add(E e) {
    
    
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
    
    
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
    
    
            lock.unlock();
        }
    }

lock方法使对集合的结构性操作都建立在getArray方法复制的副本之上,不会对原来的集合产生影响。

Vector

Vector和ArrayList都是基于数组实现的,继承关系和实现的接口都是一样的;
但ArrayList是以1.5倍方式扩容的,Vector是2倍方式扩容。
Vector构造器中可以传入当前扩容方式;
Vector是线程安全的,同步的,所以效率会低于ArrayList;
将ArrayList使用Collection.synchornizedlist(list)就可以实现线程安全。

关于LinkedList

LinkedList底层是基于双向链表实现的,它和基于数组的list相比,在内存中的空间是不连续的。
Linkedlist可以作为list使用,也可以作为queue使用。

自定义LinkedList

包括增删改查方法

import java.sql.SQLOutput;

public class MyLinkedList1<T extends  Comparable<T>>  {
    
    
    private Node<T> head;
    private Node<T> tail;
    private static class Node<E>{
    
    // this
        E value;
        Node<E> next;//后继
        Node<E> prev;//前驱

        public Node(E value) {
    
    
            this.value = value;
        }
    }
    public MyLinkedList1(Node<T> head, Node<T> tail) {
    
    
        this.head = head;
        this.tail = tail;
    }
    public void addHead(T value){
    
    
        Node<T> newNode = new Node<T>(value);
        if (head==null||tail==null){
    
    
            head=newNode;
            tail=newNode;
        }
        head.prev=newNode;
        newNode.next=head;
        head=newNode;
    }
    public void addTail(T value){
    
    
        Node<T> newNode = new Node<T>(value);
        if (tail==null||head==null){
    
    //空链表
            head=newNode;
            tail=newNode;
        }


        tail.next=newNode;
        newNode.prev=tail;

              tail=newNode;
    }

    public void removeHead(){
    
    
        if (head==null||tail==null){
    
    
            return;
        }
        if (head==tail){
    
    //只有一个结点
            head=null;
        }
        Node<T> p;
        p=head;
        head=head.next;
        head.prev=null;
        free(p);


    }
    public void free(Node<T> node){
    
    
          if (node == null){
    
    
              return;
          }
          node.prev=null;
          node.next=null;
          node.value=null;

    }
    public void removeTail(){
    
    
             if (head==null||tail==null){
    
    
                 return;
             }
             if (head==tail){
    
    
                 head=null;
                 free(head);
             }
             Node<T> q;
             q = tail;
             tail=tail.prev;
             tail.next=null;
             free(q);
    }
    public void remove(T value){
    
    
         if (head==null||tail==null){
    
    
             return;
         }
         if (head==tail&&head.value.compareTo(value)==0){
    
    
             removeHead();
         }
         Node<T> q;
         for (Node<T> p=head;p!=null;){
    
    
             if(p.value.compareTo(value) == 0){
    
    
                 q = p;
                 p=p.next;
                 if(q == head){
    
    
                     head = head.next;
                 }
             }else{
    
    
                 // p  待删除结点的前驱指向
                 q = p.next;
                 if(q!= null && q.value.compareTo(value) == 0){
    
    
                     p.next = q.next;
                     if(q.next != null) {
    
    
                         q.next.prev = p;
                     }
                 }else{
    
    
                     p = p.next;
                 }
             }
             free(q);
         }

    }
    public void change(T value,T aim,){
    
    
             for (Node<T> p =head;p!=null;p=p.next){
    
    
                 if (p.value.compareTo(value)==0){
    
    
                         p.value=aim;
                 }
             }
    }
    public boolean contain(T value){
    
    
             for (Node<T> p =head;p!=null;p=p.next){
    
    
                  if (p.value.compareTo(value)==0){
    
    
                      return true;
                  }

             }
             return false;
    }
    public void show(){
    
    
        for (Node<T> p =head;p!=null;p=p.next){
    
    
            System.out.println(p.value+" ");
        }
        System.out.println( );
    }
}

LinkedList和ArrayList的区别和联系

ArrayList和LinkedList都是实现了List接口的容器类,用于存储一系列的对象引用。
他们都可以对元素的增删改查进行操作。
1.ArrayList底层由数组实现,内存中是连续的内存空间,需要维护容量大小;Linkedlist底层由链表实现,内存是非连续的内存空间,不需要维护容量大小。
2.当实现get和set操作时,ArrayList比LinkedList的效率更高,因为LinkedList是线性的数据存储方式,所以需要移动指针
从前往后依次查找。
当实现增加和删除操作时,LinkedList比ArrayList的效率更高,因为ArrayList是数组,进行增删操作时,
会对数据的下标索引造成影响,需要进行数据的移动。
3.ArrayList需要手动设置固定大小的容量,但使用方便,创建数组,添加数据,然后通过调用下标进行使用;
LinkedList能够动态的随数据量的变化而变化,但不便于使用。

猜你喜欢

转载自blog.csdn.net/qq_40939454/article/details/108886531