zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    解决 minicom 不能接收键盘输入问题
    Qt 使用tablib获取多媒体tag信息
    博客园scribefire配置
    Connection Manager简称connman
    【转】使用ssh-keygen和ssh-copy-id三步实现SSH无密码登录
    ubuntu 更改U盘设备分区/dev/sdb4 标识
    Qt 自动化测试Test cutedriver
    在Sublime2/3中使用build命令编译TypeScript文件
    移动端Web适配单位rem的坑
    禁止保存,拖拽图片,禁用右键和F12
  • 原文地址:https://www.cnblogs.com/fubaizhaizhuren/p/Collection.html
Copyright © 2011-2022 走看看