List 与 Set

一、简介

List 与 Set 是两个常用的容器接口,其中List的特点是有序,Set的特点是元素唯一。
常用的List实现有ArrayList、LinkedList、Vector。
常用的Set实现有HashSet、LinkedHashSet、TreeSet。

二、List实现

1、ArrayList:
ArrayList底层由数组实现,因此查询效率很高,而对于插入删除操作,需要将插入、删除的元素后的所有元素右移或前移,所以在数据插入删除操作频繁时不建议使用,查询情况较多的情况下ArrayList是个很好的选择。
2、LinkedList:
LinkedList底层由双端链表实现,对于插入、删除操作,仅需要改变前一个节点和后一个节点的指向,即可完成插入、删除操作,而对于查询操作,链表需要从头节点或尾节点开始遍历,所以查询效率低下。
3、Vector:
Vector实现与ArrayList类似,但大多数公共方法由synchronized修饰,所以是线程安全的,但也因此效率较低,所以在没有线程安全要求的情况下,尽量不使用该实现。另外Vector与ArrayList在新增时会有扩容操作,ArrayList默认每次增长50%,Vector增长100%。
4、ArrayList扩容实现:

public boolean add(E e) {
       //添加操作前的扩容操作
       ensureCapacityInternal(size + 1);  // Increments modCount!!
       elementData[size++] = e;
       return true;
 }
 //扩容函数
 private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
 //计算最小扩容数
 private static int calculateCapacity(Object[] elementData, int minCapacity) {
       //使用无参构造器时,默认增长因子是10,所以在长度较小时,默认扩容至10(使用其他构造器则不使用默认的增长因子)
       if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
           return Math.max(DEFAULT_CAPACITY, minCapacity);
       }
       return minCapacity;
   }
 private void ensureExplicitCapacity(int minCapacity) {
      modCount++;
      // 判断是否需要扩容
      if (minCapacity - elementData.length > 0)
          grow(minCapacity);
  }
private void grow(int minCapacity) {
      // overflow-conscious code
      int oldCapacity = elementData.length;
      //新的数组长度等于原数组的1.5倍
      int newCapacity = oldCapacity + (oldCapacity >> 1);
      //传入的容器长度小于原数组的1.5倍,则扩容至1.5倍
      if (newCapacity - minCapacity < 0)
          newCapacity = minCapacity;
      //容器极限长度的处理
      if (newCapacity - MAX_ARRAY_SIZE > 0)
          newCapacity = hugeCapacity(minCapacity);
      // 将原数组复制到新数组中
      elementData = Arrays.copyOf(elementData, newCapacity);
}
//大于默认的容器最大长度是,将长度置为Integer最大值
private static int hugeCapacity(int minCapacity) {
       if (minCapacity < 0) // overflow
           throw new OutOfMemoryError();
       return (minCapacity > MAX_ARRAY_SIZE) ?
           Integer.MAX_VALUE :
           MAX_ARRAY_SIZE;
   }

可以看到,扩容在前期长度较小时,是直接扩容到10的,避免前期的频繁扩容操作。
其中每次扩容50%体现在int newCapacity = oldCapacity + (oldCapacity >> 1);右移操作就等于除以2。
5、Vector扩容实现:

public synchronized void addElement(E obj) {
    modCount++;
    //扩容
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = obj;
}
private void ensureCapacityHelper(int minCapacity) {
    // 判断是否需要扩容
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    //扩容为原长度2倍
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                     capacityIncrement : oldCapacity);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        //容器极限长度的处理,与ArrayList相同
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);
}

三、Set简介:

1、HashSet:
底层通过HashMap实现,无序,因为将HashMap的键作为Set的值,所以可以防止出现重复值。
2、LinkedHashSet:
底层通过LinkedHash实现,通过链表方式可以实现有序的Set,值得一提的是,LinkedHashSet中仅有几个构造函数,具体实现实际是继承了HashSet,在HashSet中有提供包访问权限的构造函数,使用的是LinkedHashMap。
3、TreeSet:
底层通过TreeMap实现,其中提供的排序的方法,这里的排序与LinkedHashSet的有序是不一样的,这里的排序是指通过存入元素的数值大小进行排序(实现Comparable接口),有序是指保持了插入顺序,遍历时是按插入顺序便利的。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值