java集合类

1、Collection和Collections的区别?

(1)Collection是一个接口,为集合对象的基本操作提供通用的接口放法。

(2)Collections是一个工具类,里面包含各种对集合的操作放法,是服务于Collection框架的工具类。不能实例化。

       如Collections.sort()方法就可以对一个ArrayList对象进行排序。

2、Collection和Map框架结构图

(1)下图均为接口

(2)下图为接口实现类(白色部分为实现类)

3、实现类详解

 (1)ArrayList和LinkedList

    I ArrayList

   ArrayList底层是数组实现,构造ArrayList的时候,默认数组的初始化容量为10,容器为Object[] elementData。向集合添加元素的时候,调用add方法,比如list.add("a");add方法做的操作是:elementData[size++] = e; 然后元素就被存放进了elementData。

源码,add方法中先调用ensureCapacity方法对原数组长度进行扩充,扩充方式为,通过Arrays类的copyOf方法对原数组进行拷贝,长度为原数组的1.5倍+1。
然后把扩容后的新数组实例对象地址赋值给elementData引用类型变量。扩容完毕。这就是ArrayList为可变数组的原理。。。。

 1 public class ArrayList<E> extends AbstractList<E> implements List<E> {  
 2     private transient Object[] elementData;  
 3       
 4     public ArrayList(int initialCapacity) {  
 5         super();  
 6         if (initialCapacity < 0)  
 7             throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);  
 8         this.elementData = new Object[initialCapacity];  
 9     }  
10     //Constructs an empty list with an initial capacity of ten.  
11     public ArrayList() {  
12         this(10);  
13     }  
14     public boolean add(E e) {  
15         ensureCapacity(size + 1);  // 扩充长度  
16         elementData[size++] = e; // 先赋值,后进行size++。所以是从[0]开始存。  
17         return true;  
18     }  
19     public void ensureCapacity(int minCapacity) {  
20         modCount++;  
21         int oldCapacity = elementData.length; // 旧集合长度  
22         if (minCapacity > oldCapacity) {  
23             Object oldData[] = elementData; // 旧集合数据  
24             int newCapacity = (oldCapacity * 3)/2 + 1; // 计算新长度,旧长度的1.5倍+1  
25                 if (newCapacity < minCapacity)  
26                     newCapacity = minCapacity;  
27                 // minCapacity is usually close to size, so this is a win:  
28                 elementData = Arrays.copyOf(elementData, newCapacity); // 这就是传说中的可变集合。用新长度复制原数组。  
29         }  
30     }  
31     public E get(int index) {  
32         RangeCheck(index);  
33         return (E) elementData[index];  
34     }  
35 }  
当add()容量够时,就是直接在后面添加,速度很快。
当add()容量不够时,就将新建一个更大的数组,然后把旧数组的内容复制过去。
当在中间位置插入时,会把插入点及后面的数据后移一个位置。然后插入。
当在中间位置删除时,会将删除点后面的数据前移一个位置。

所以说任何时间点,其内存都是连续的,随机索引访问效率很高。
插入,删除效率低。或者容量满时add()效率低。

  ArrayList例子:

  

II  LinkedList

LinkedList底层数据结构是基于双向链表的。且头结点中不存放任何数据

既然是双向链表,那么必定存在一种数据结构——我们可以称之为节点,节点实例保存业务数据,前一个节点的位置信息和后一个节点位置信息,如下图所示:

节点类Entry

private static class Entry<E> {
   E element;
    Entry<E> next;
    Entry<E> previous;

    Entry(E element, Entry<E> next, Entry<E> previous) {
        this.element = element;
        this.next = next;
        this.previous = previous;
   }
}

节点类很简单,element存放业务数据,previous与next分别存放前后节点的信息(在数据结构中我们通常称之为前后节点的指针)。

LinkedList的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;
    }

add执行步骤

  (1)

其中,header是一个Entry对象,存储了当前节点的previous(前一节点)和next(后置节点),

(2)

初始化一个预添加的Entry实例(newEntry)。

Entry newEntry = newEntry(e, entry, entry.previous);

(3):调整新加入节点和头结点(header)的前后指针。

newEntry.previous.next = newEntry;

newEntry.previous即header(节点一的previous),newEntry.previous.next即header(节点一)的next指向newEntry实例。在上图中应该是“4号线”指向newEntry。

newEntry.next.previous = newEntry;

newEntry.next即header,newEntry.next.previous即header的previous指向newEntry实例。在上图中应该是“3号线”指向newEntry。

添加后续数据情况和上述一致,LinkedList实例是没有容量限制的。

Java中数据存储方式最底层的两种结构,一种是数组,另一种就是链表,数组的特点:连续空间,寻址迅速,但是在删除或者添加元素的时候需要有较大幅度的移动,

所以查询速度快,增删较慢。而链表正好相反,由于空间不连续,寻址困难,增删元素只需修改指针,所以查询慢、增删快

 III  hashcode

  查看Object类的源码可知,hashcode是一个本地方法,

public native int hashCode();

Integer类型数据的求hashcode方法

   public static int hashCode(int value) {
        return value;
    }

即数字本身

String 类求hashcode方法

    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

hashCode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值 ,

如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果,注:这里说的equals(Object) 方法是指Object类中未被子类重写过的equals方法。
如果两个hashCode()返回的结果相等,则两个对象的equals方法不一定相等。
IV hashmap和hastable区别

1)、HashMap是非线程安全的,HashTable是线程安全的。

2)、HashMap的键和值都允许有null值存在,而HashTable则不行。

3)、因为线程安全的问题,HashMap效率比HashTable的要高。

 

参考http://www.cnblogs.com/ITtangtang/p/3948610.html#a1

原文地址:https://www.cnblogs.com/fubaizhaizhuren/p/Collection.html