zoukankan      html  css  js  c++  java
  • ArrayList、LinkedList、CopyOnWriteArrayList

    目录:

      1)ArrayList

      2)LinkedList

      3)CopyOnWriteArrayList

    1)ArrayList

    概况:

    public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable

    说明:

    1)很多实现类都要继承一个抽象类,比如ArrayList<E>继承AbstractList<E>,那是因为如果你就实现了List<E>,那样的话得重写多少抽象方法啊。不过,一旦你继承了AbstractList<E>,因为AbstractList<E>已经重新了很多抽象方法,所以你只需要重写一部分抽象方法就可以了,不那么累嘛;

    2)ArrayList继承AbstractList抽象父类,实现了List接口(规定了List的操作规范)、RandomAccess(可随机访问)、Cloneable(可拷贝)、Serializable(可序列化)。这个至少要大概知道

    代码:

    Collections接口操作list

    Collections.shuffle(List<T> list);//随机输出元素
    Collections.reverse(List<T> list); //List元素内反转,因为list内的元素是有序的
    Collections.max(List<T> list);//最大值
    Collections.min(List<T> list);//最小值
    Collections.sort(List<T> list);//排序
    Collections.emptyList();//返回一个空集合
    View Code

     数组与集合之间的转换

    /**
     *     数组转集合:不能增删,否则抛异常,集合的其它方法都可以
     */
    private static void arrToList() {                     
        String[] arr = {"a","b","c"};                     
        List<String> list = Arrays.asList(arr);           
        System.out.println(list.size());                  
                                                          
        int[] ints = {1,2,3,4};                           
        List<int[]> list2 = Arrays.asList(ints);          
        System.out.println(list2.size());//长度为1,明显不正确           
                                                          
        //用包装类,所以所以记得,一定要用包装类                                            
        Integer[] integers = {1,2,3,4,5,6};               
        List<Integer> list3 = Arrays.asList(integers);    
        System.out.println(list3.size());//长度为6,搞定了           
    }    
    
    /**
     *      集合转数组
     */
    public static void main(String args[]) {                    
        List<String> list = new ArrayList<>();                  
        list.add("A");                                          
        list.add("B");                                          
        list.add("C");                                          
        list.add("D");                                          
        list.add("E");                                          
        //方法一:                                                  
        String[] str03 = list.toArray(new String[list.size()]); 
        for (String str : str03) {                              
            System.out.print(str);                              
        }                                                       
        //方法二:                                                  
        Object[] objs = list.toArray();                         
        for (Object obj : objs) {                               
            System.out.print((String)obj);                      
        }                                                       
    }
    View Code

    去掉list中的重复元素(字符串)

    private static void removeRepeat() {
    
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("a");
        list.add("b");
        list.add("b");
        list.add("b");
        list.add("c");
        list.add("c");
        list.add("c");
        list.add("c");
        
    //    方法一:
        Set<String> set01 = new HashSet<>(list);
        list.clear();
        list = new ArrayList<>(set01);
        
    //    方法二:
        Set<String> set02 = new HashSet<>();
        set02.addAll(list);
        list.clear();
        list.addAll(set02);
        
    //    方法三:创建一个新的list,没有的话就加上去
        Iterator<String> iterator = list.iterator();
        List<String> list2 = new ArrayList<>();
        while (iterator.hasNext()) {
            String string = (String) iterator.next();
            if (!list2.contains(string)) {
                list2.add(string);
            }
        }
        
    }
    View Code

    去掉list中的重复元素(对象)

    /*                                                      
     * 主要注意点就是要复写Object类的equals方法,Object类的equals方法是地址值比较                      
     * 我们要变成对象比较                                                              
     */                                                                       
    private static void removeRepeat02() {                                    
        List<Person> list = new ArrayList<>();                                
        List<Person> list2 = new ArrayList<>();                               
        list.add(new Person("张三",23));                                        
        list.add(new Person("李四",24));                                        
        list.add(new Person("张三",23));                                        
        list.add(new Person("李四",24));                                        
        list.add(new Person("张三",23));                                        
        list.add(new Person("王五",25));                                        
        Iterator<Person> iterator = list.iterator();                          
        while (iterator.hasNext()) {                                          
            Person person = iterator.next();                                  
            if (!list2.contains(person)) {                                    
                list2.add(person);                                            
            }                                                                 
        }                                                                     
    }
    
    class Person {
        public String name;
        public int age;
        ...省略构造方法,tostring方法,setget方法/*
         * 自定义,对象内容比较
         * @see java.lang.Object#equals(java.lang.Object)
         */
        @Override
        public boolean equals(Object obj) {
            Person p = (Person) obj;
            return this.name.equals(p.name) && this.age == p.age;
        }
        
    }     
    
    
    为什么要复写equals方法?
    public boolean contains(Object o) {
        return indexOf(o) >= 0;        
    }    
    遍历list,用list里面的对象作比较,所以必须覆写equals方法。
    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;                           
    }            
    (类似list的contains方法,list的remove方法底层也是依赖于equals方法的)
    View Code

    集合遍历的时候增减(Iterator)记住:ConcurrentModificationException(增减的时候只有用Iterator才不会报错)

    private static void method02() {                
        List<String> list = new ArrayList<>();      
        list.add("A");                              
        list.add("B");                              
        list.add("B");                              
        list.add("C");                              
        list.add("D");                              
        list.add("E");                              
        list.add("B");                              
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {                
            String string = iterator.next();        
            if ("B".equals(string)) {               
                iterator.remove();                  
            }                                       
        }                                           
    }
    View Code

    分页

    public class ListPage {
        private PageModel getListPage(List<String> listNotPage, int pageSize, int currentPage) {
            List<String> listPage = Collections.emptyList();
            int totalSize = 0;
            if (!listNotPage.isEmpty()) {
                //对list进行分页
                int fromIndex = (currentPage - 1) * pageSize;
                totalSize = listNotPage.size();
                if (totalSize <= fromIndex) {
                    return new PageModel(listPage, totalSize);
                }
                //所以下面的totalSize肯定大于fromIndex,所以肯定有数据,同时要保证toIndex大于FromIndex
                if (totalSize % pageSize == 0) {
                    listPage = listNotPage.subList(fromIndex, currentPage * pageSize);
                } else {
                    int totalPage = totalSize / pageSize + 1;
                    listPage = listNotPage.subList(fromIndex, currentPage == totalPage ? totalSize : currentPage * pageSize);
                }
            } 
            return new PageModel(listPage, totalSize);
        }
    }
    class PageModel {
        private List<String> list;
        private long totalSize;
        public PageModel(List<String> list, long totalSize) {
            super();
            this.list = list;
            this.totalSize = totalSize;
        }
        // set,get........
    }
    View Code

    关于set方法

    public static void main(String[] args) {     
                                                 
        List<String> list = new ArrayList<>();   
        list.add("1");                           
        list.add("2");                           
        list.add(0, "3");                        
        System.out.println(list); // 输出 [3, 1, 2]
                                                 
        List<String> list02 = new ArrayList<>(); 
        list02.add("1");                         
        list02.add("2");                         
        list02.set(0, "3");                      
        System.out.println(list02); // [3, 2]    
                                                 
    }
    View Code

    关于removeAll与retainAll

    // 去掉相同的
    public static void main(String[] args) {   
        List<String> list = new ArrayList<>(); 
        list.add("a");                         
        list.add("b");                         
        list.add("c");                         
        list.add("b");                         
        List<String> list2 = new ArrayList<>();
        list2.add("a");                        
        list2.add("b");                        
        list2.add("d");                        
        list.removeAll(list2);                 
        System.out.println(list); // 输出:[c]    
    }                                          
    // 保留相同的,即取交集
    public static void main(String[] args) {     
        List<String> list = new ArrayList<>();   
        list.add("a");                           
        list.add("b");                           
        list.add("c");                           
        list.add("b");                           
        List<String> list2 = new ArrayList<>();  
        list2.add("a");                          
        list2.add("b");                          
        list2.add("d");                          
        list.retainAll(list2);                   
        System.out.println(list); //输出:[a, b, b] 
    }
    View Code

    源码:

    常量:注意size 和 elementData 的区别,更多具体自己一定要去看源码的英文注释吧,你自己会看得懂的

    private static final long serialVersionUID = 8683452581122892189L;
    private static final int DEFAULT_CAPACITY = 10; // Default initial capacity.                         
    private static final Object[] EMPTY_ELEMENTDATA = {};// Shared empty array instance used for empty instances.                         
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 看不懂这个跟上面的,有什么区别         
    transient Object[] elementData; // 自己看源码英文注释
    private int size; // 自己看源码英文注释
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;// 最大数组容量

     构造方法

        /**
         *     初始化集合大小创建 ArrayList 集合。当大于0时,给定多少那就初始化多大的空间;当等于0时,创建一个空数组(空间为0);当小于0时,抛出异常。
         * @param initialCapacity
         */
        public ArrayList(int initialCapacity) {
            if (initialCapacity > 0) {
                this.elementData = new Object[initialCapacity]; // 从这里就可以看出来,是占用的空间,开辟的空间
            } else if (initialCapacity == 0) {
                this.elementData = EMPTY_ELEMENTDATA;
            } else {
                throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
            }
        }
        
        /**
         * Constructs an empty list with an initial capacity of ten.
         *         卧槽,空参构造默认占用空间为0,如果put方法向其中添加一个元素的时候,变为10,
         */
        public ArrayList() {
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; 
        }
    View Code

     add(),一定要弄清楚elementData与size的区别,其实这里的代码也没啥啊

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // size 为该数组空间内实际上有多少个元素elementData,所以该参数就是增加之后最少的空间
        elementData[size++] = e;
        return true;
    }
    
    /**
     * calculateCapacity(elementData, minCapacity):计算出最后要多少 capacity 之后,就进行实际的操作
     * @param minCapacity  扩容后所要求的最小容量
     */
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    
    /**
     *
     * @param elementData 记住这里的 elementData 是一个成员变量
     * @param minCapacity 扩容后所要求的最小容量
     * @return 到底最后要多少 capacity
     */
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);  // 如果原始容量为空的话,哈哈,取默认初始化容量10和最小容量的这两个当中的最大值(空参构造向其中put一个元素初始容量变为10)
        }
        return minCapacity; // 如果原始容量不为空(不为空的话,也不可能小于 DEFAULT_CAPACITY = 10 的啦,),则返回所要求的最小容量
    }
    
    /**
     * 这里里可以知道,数组容量和数组里面的元素个数是可以相等的,相等的情况下是不进行扩容的
     * @param minCapacity
     */
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // overflow-conscious code
        // 如果所需的最小容量大,说明空间不够嘛,就需要扩容
        if (minCapacity - elementData.length > 0) {
            grow(minCapacity);
        }
    }
    
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length; // 这里更进一步elementData的意思
        int newCapacity = oldCapacity + (oldCapacity >> 1);// 扩容,新容量为旧容量的1.5倍
        if (newCapacity - minCapacity < 0) {  // 1.5陪容量还不够最小容量的话,取最小容量
            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;
    }

     set(),好好体会 index >= size 中的 size

        public E set(int index, E element) {
            rangeCheck(index);
            E oldValue = elementData(index);
            elementData[index] = element;
            return oldValue;
        }
        
        private void rangeCheck(int index) {
            if (index >= size)   
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
        
        E elementData(int index) {
            return (E) elementData[index];
        }
    View Code

     indexOf(),ArrayList中的元素可以是null元素,lastIndexOf 就是反向查找的啦 for(int i = size-1; i >= 0; i--)

        /**
         * Returns the index of the first occurrence of the specified element
         * in this list, or -1 if this list does not contain the element.
         * More formally, returns the lowest index <tt>i</tt> such that
         * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
         * or -1 if there is no such index.
         */
        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;
        }
    View Code

     get()

        public E get(int index) {
            rangeCheck(index);
            return elementData(index);
        }
    View Code

    2)LinkedList

    3)CopyOnWriteArrayList

    参考博客:

    1)【目录】集合框架目录   ---》 【集合框架】JDK1.8源码分析之ArrayList(六)

    2)Java 集合详解

    3)JDK1.8源码(五)——java.util.ArrayList 类

    4)JDK1.8源码(六)——java.util.LinkedList 类   (写得真的很好,很用心啊)

  • 相关阅读:
    Tomcat下使用war包发布项目
    shell编程报错:“syntax error near unexpected token `”
    undo表空间不足,ORA-30036: unable to extend segment by 8 in undo tablespace 'UNDOTBS2'
    HTML快速入门
    HTTP协议快速入门
    Java Web应用的开发模式
    使用Jekyll搭建免费的Github Pages个人博客
    前端模拟API数据的两种方式
    Node.js学习笔记
    socket.io笔记
  • 原文地址:https://www.cnblogs.com/ericguoxiaofeng/p/10321580.html
Copyright © 2011-2022 走看看