ArrayList 【目录】集合框架目录 【集合框架】JDK1.8源码分析之ArrayList(六) Java 集合详解 JDK1.8源码(五)——java.util.ArrayList 类 JDK1.8源码(五)——java.util.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

源码:

常量

    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; // 实际元素大小,默认为0;所包含的元素个数有多少啊
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;// 最大数组容量
View Code

 构造方法

    /**
     *     初始化集合大小创建 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的区别

    /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // size 为该数组空间内实际上有多少个元素elementData,所以该参数就是增加之后最少的空间
        elementData[size++] = e;
        return true;
    }
    
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);  // 如果原始容量为空的话,哈哈,取默认初始化容量10和最小容量的这两个当中的最大值(空参构造向其中put一个元素初始容量变为10)
        }
        return 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;
    }
View Code

 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

参考博客:

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

2)Java 集合详解

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

图片来源:

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

猜你喜欢

转载自www.cnblogs.com/ericguoxiaofeng/p/10321580.html