java容器

容器是用于持有对象的。最好的持有对象的方法是数组,但是数组的长度固定。容器的顶层接口是Collections, 其中包含List,set接口, Map接口不属于Collections接口的。



ArrayList

是动态数组,从类的定义上看,


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

有几个特点,支持泛型,

RandomAccess是一个标记接口,接口内没有定义任何内容。

 实现了Cloneable接口的类,可以调用Object.clone方法返回该对象的浅拷贝。

通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。序列化接口没有方法或字段,仅用于标识可序列化的语义。


ArrayList的属性,两个私有属性:

/** 
      * The array buffer into which the elements of the ArrayList are stored. 
      * The capacity of the ArrayList is the length of this array buffer. 
      */  
     private transient Object[] elementData;  
   
     /** 
      * The size of the ArrayList (the number of elements it contains). 
      * 
      * @serial 
      */  
     private int size;  

transient是关键字,用来表示一个域不是该对象串行化的一部分。

构造函数有3个

/** 
      * Constructs an empty list with the specified initial capacity. 
      */  
     public ArrayList(int initialCapacity) {  
     super();  
         if (initialCapacity < 0)  
             throw new IllegalArgumentException("Illegal Capacity: "+  
                                                initialCapacity);  
     this.elementData = new Object[initialCapacity];  
     }  
   
     /** 
      * Constructs an empty list with an initial capacity of ten. 
      */  
     public ArrayList() {  
     this(10);  
     }  
   
     /** 
      * Constructs a list containing the elements of the specified 
      * collection, in the order they are returned by the collection's 
      * iterator. 
      */  
     public ArrayList(Collection<? extends E> c) {  
     elementData = c.toArray();  
     size = elementData.length;  
     // c.toArray might (incorrectly) not return Object[] (see 6260652)  
     if (elementData.getClass() != Object[].class)  
         elementData = Arrays.copyOf(elementData, size, Object[].class);  
     }  


1:初始化一个指定大小的数组

2:无参数构造函数,默认数组大小是10

3:用一个Collection创建。


添加一个元素:

public boolean add(E e) {  
    ensureCapacity(size + 1);  // Increments modCount!!  
    elementData[size++] = e;  
    return true;  
    }

/** 
      * Increases the capacity of this <tt>ArrayList</tt> instance, if 
      * necessary, to ensure that it can hold at least the number of elements 
      * specified by the minimum capacity argument. 
      * 
      * @param   minCapacity   the desired minimum capacity 
      */  
     public void ensureCapacity(int minCapacity) {  
     modCount++;  
     int oldCapacity = elementData.length;  
     if (minCapacity > oldCapacity) {  
         Object oldData[] = elementData;  
         int newCapacity = (oldCapacity * 3)/2 + 1;  
             if (newCapacity < minCapacity)  
         newCapacity = minCapacity;  
             // minCapacity is usually close to size, so this is a win:  
             elementData = Arrays.copyOf(elementData, newCapacity);  
     }  
     }

如果超出数组目前的大小,则数组的长度变为原来的*3/2 + 1;


在指定的位置插入元素

public void add(int index, E element) {  
     if (index > size || index < 0)  
         throw new IndexOutOfBoundsException(  
         "Index: "+index+", Size: "+size);  
   
     ensureCapacity(size+1);  // Increments modCount!!  
     System.arraycopy(elementData, index, elementData, index + 1,  
              size - index);  
     elementData[index] = element;  
     size++;  
     } 

原理就是把后边的数组都向右移动一位。


取指定位置的元素

public E get(int index) {  
     RangeCheck(index);  
  
     return (E) elementData[index];  
     } 


移除某个位置的元素

public E remove(int index) {  
     RangeCheck(index);  
     modCount++;  
     E oldValue = (E) elementData[index];  
     int numMoved = size - index - 1;  
     if (numMoved > 0)  
         System.arraycopy(elementData, index+1, elementData, index,  
                  numMoved);  
     elementData[--size] = null; <span style="color:#ff0000;">// Let gc do its work </span> 
     return oldValue;  
     } 


LinkedList

底层是双向循环链表,头结点不存放数据


public class LinkedList<E>
     extends AbstractSequentialList<E>
     implements List<E>, Deque<E>, Cloneable, java.io.Serializable

LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。
LinkedList 实现 List 接口,能对它进行队列操作。
LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。
LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。
LinkedList 是非同步的。


还是两个私有属性

1 private transient Entry<E> header = new Entry<E>(null, null, null);
2 private transient int size = 0;

1 private static class Entry<E> {
 2    E element;
 3     Entry<E> next;
 4     Entry<E> previous;
 5 
 6     Entry(E element, Entry<E> next, Entry<E> previous) {
 7         this.element = element;
 8         this.next = next;
 9         this.previous = previous;
10    }
11 }

两个构造方法:

1 public LinkedList() {
2     header.next = header.previous = header;
3 }
4 public LinkedList(Collection<? extends E> c) {
5     this();
6    addAll(c);
7 }


第一个构造方法不接受参数,将header实例的previous和next全部指向header实例(注意, 这个是一个双向循环链表,如果不是循环链表,空链表的情况应该是header节点的前一节点和后一节点均为null),这样整个链表其实就只有header一个节点,用于表示一个空的链表。

添加元素,add:

     // 将元素(E)添加到LinkedList中
     public boolean add(E e) {
         // 将节点(节点数据是e)添加到表头(header)之前。
         // 即,将节点添加到双向链表的末端。
         addBefore(e, header);
         return true;
     }

     public void add(int index, E element) {
         addBefore(element, (index==size ? header : entry(index)));
     }
    
    private Entry<E> addBefore(E e, Entry<E> entry) {
         Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
         newEntry.previous.next = newEntry;
         newEntry.next.previous = newEntry;
         size++;
         modCount++;
         return newEntry;
    }

删除元素:

逻辑简单,但是个人觉得要先要遍历链表找到这个元素,在删除。

 1 private E remove(Entry<E> e) {
 2     if (e == header)
 3         throw new NoSuchElementException();
 4     // 保留将被移除的节点e的内容
 5     E result = e.element;
 6    // 将前一节点的next引用赋值为e的下一节点
 7     e.previous.next = e.next;
 8    // 将e的下一节点的previous赋值为e的上一节点
 9     e.next.previous = e.previous;
10    // 上面两条语句的执行已经导致了无法在链表中访问到e节点,而下面解除了e节点对前后节点的引用
11    e.next = e.previous = null;
12   // 将被移除的节点的内容设为null
13   e.element = null;
14   // 修改size大小
15   size--;
16   modCount++;
17   // 返回移除节点e的内容
18   return result;
19 }
复制代码

获取某个元素,get,remove的时候要调用

// 获取双向链表中指定位置的节点    
    private Entry<E> entry(int index) {    
        if (index < 0 || index >= size)    
            throw new IndexOutOfBoundsException("Index: "+index+    
                                                ", Size: "+size);    
        Entry<E> e = header;    
        // 获取index处的节点。    
        // 若index < 双向链表长度的1/2,则从前先后查找;    
        // 否则,从后向前查找。    
        if (index < (size >> 1)) {    
            for (int i = 0; i <= index; i++)    
                e = e.next;    
        } else {    
            for (int i = size; i > index; i--)    
                e = e.previous;    
        }    
        return e;    
    }

若index < size/2;从前往后;若index >= size/2;从后往前。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值