Java集合框架学习

5 篇文章 0 订阅

今天看了一下集合框架,其实指的就是Collection接口和Map接口,其中Collection接口是Iterable接口的子接口。而Map接口上面已经没有父类接口了。
其中,Iterable接口包含三个方法

一、Collection接口
从Collection接口,就是我们的框架内容了,大致将一下,Collection接口下面有很多的子接口,其他的没用过,但是有三个我们经常碰见的,就是Set , List,Queue
List:是一种底层是数组实现的, 元素可重复的有序集合,下面有很多实现,比如ArrayList,LinkedList , Vector等
Set:底层是hash表实现的,不可重复的无序集合,下面的实现有HashSet,TreeSet等
Queue:用于装载先进先出原则的数据 ,下面的实现有Dequeue,LinkedList等。
这里写图片描述

下面来介绍集中常用的实现
1、ArrayList,最常用的集合,底层是数组,源码中的定义如下,和父类List接口一直,是可以存放重复的元素 ,且存放的元素是有序的。

 /**
   * The array buffer into which the elements of the ArrayList are stored.
    * The capacity of the ArrayList is the length of this array buffer. Any
    * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
    * will be expanded to DEFAULT_CAPACITY when the first element is added.
    */
   transient Object[] elementData; // non-private to simplify nested class access

ArrayList与普通的数组有什么区别呢?
最大的区别就是数组的长度是固定的,不可变的,一旦超出数组的长度范围是会报错的,而ArrayList底层虽然也是数组,但是长度却是可变的,每次增加元素是,也就是add方法,都将会检查一遍上面定义的这个数组的长度是否足够,不够的话,将新建一个新的数组,并将老的数组复制到新的数组当中。

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

   private void ensureCapacityInternal(int minCapacity) {
      if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
          minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
      }

      ensureExplicitCapacity(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;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            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);
    }

第二点就是,集合做到动态扩容牺牲的是自身的效率,因此,数组的效率是比集合要高的。
第三,集合定义了remove()方法删除自身元素,而数组没有。
第四点,集合存入对象时,抛弃类型信息,所有对象屏蔽为Object,编译时不检查类型,但是运行时会报错。而数组一旦定义好了,如果存放不同类型的数据,编译就会不通过。这个区别总结起来就是,数组只能存放单一类型,而集合可以存放任意类型,默认就是Object,所有对象。

当然了,集合和数组也可以转换,只限于集合存放单一类型
集合–>数组,List.toArray()
数组–>集合,Array.asList()

2、LinkedList

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

看定义我们就知道,LinkedList是实现了List和Queue接口的。底层是链表实现的。LinkedList通过代价较低的在List中间进行插入和删除操作,提供了优化的顺序访问。也即是说,相比于ArrayList,LinkedList的插入删除速度是比ArrayList慢的,而查询的速度却更加的快。
源码中,unlinkLast()方法和unlinkFirst(),顾名思义,也就是pollLat()he pollFirst()的调用,里面是这么写的:

private E unlinkFirst(Node<E> f) {
        // assert f == first && f != null;
        final E element = f.item;
        final Node<E> next = f.next;
        f.item = null;
        f.next = null; // help GC
        first = next;
        if (next == null)
            last = null;
        else
            next.prev = null;
        size--;
        modCount++;
        return element;
    }

    /**
     * Unlinks non-null last node l.
     */
    private E unlinkLast(Node<E> l) {
        // assert l == last && l != null;
        final E element = l.item;
        final Node<E> prev = l.prev;
        l.item = null;
        l.prev = null; // help GC
        last = prev;
        if (prev == null)
            first = null;
        else
            prev.next = null;
        size--;
        modCount++;
        return element;
    }

里面的这句help GC很有意思,意思是让某个对象=null,就能被GC掉,否则这个对象永远不会被GC,为什么呢?翻翻JVM书可以找到答案。

3、Vector
List的另一种实现,使用方法和ArrayList一样,但是,人家是线程安全的,所有操作元素的方法都加了synchronized关键字,这也是两者的最大的区别。
两者还有一个不同点,就是两者的扩容方式:
ArrayList:初始容量*3/2+1
Vector:默认扩充两倍。

4、HashSet
说HashSet之前先看看下面的HashMap,因为HashSet是对HashMap的一层包装,内部就是一个HashMap,没什么区别。先看HashMap。

5、HashMap
Map接口的实现类。以key/value键值对存放数据,key值不允许为空,value可以为空,且由于容器可能会对元素进行重新hash,HashMap无法保证元素是有序的。
重新Hash之后,有可能会产生冲突,HashSet处理冲突时候,采用的是冲突链表方式
HashMap的性能问题,一般来说,put和get是可以在常数时间内完成,但是,如果要对HashMap进行迭代,就需要去遍历整个HashMap和冲突链表。因此,如果是迭代次数比较多的场景,HashMap的初始值不应该设置太大。
有两个参数可以影响HashMap的性能,一个是初始容量(inital capacity)和负载系数(load factor),负载系数指的是自动扩充容量的临界值。当entry的数量大于(初始容量*和负载系数)时,HashMap将进行扩容,且重新计算Hash。所以,对于插入操作较多的场景,将初始值设置稍大,可以减少重新Hash的次数。
另外,将对象放到HashMap中时,需要注意两个方法,hashCode()和equals(),当插入对象时,是通过hashCode计算Hash值判断对象应该插入到什么位置,当Hash值重复时,就要通过equals()方法去判断是不是同一个对象。所以说,如果要将自定义的对象放入到HashMap中,需要重写这两个方法。

6、HashTable
也是Map的实现类,与HashMap一样,唯一不同的就是,HashTable是同步的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值