Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

xaing/java-learn

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

3 Commits

Repository files navigation

Sun JDK集合

关于集合的理解,需要从普通集合和能够支持并发的集合两个场景来进行,弄清楚每个典型的集合类的使用场景,每个集合的局限,以及和其他集合的比较。如何选择出合适的类来满足特定的需求,直接考验开发者的功底。

掌握这些类集合类的实现原理,以及在不同场景下的性能表现

普通集合包

理解集合包,主要从Collection和Map接口进行理解,然后考虑它们的衍生类
Collection <-- List <-- (ArrayList, LinkedList, Vector, Stack)
Collection <-- Set <-- (HashSet, TreeSet)

集合集成全貌

ArrayList

需要注意一下几点:

  • ArrayList是基于数组方式实现的,无容量的限制
  • ArrayList在执行插入元素时可能要扩容,在删除元素时并不会减小数组的容量(除非调用trimToSize()方法)
  • 在查找元素时要遍历数组,对于非null的元素采取equals的方式寻找
  • ArrayList是非线程安全的
  • add、get性能都不错,remove性能较差

LinkedList

  • LiinkedList基于双向链表机制实现
  • LinkedList在插入元素时,须创建一个新的Entry对象,并切换相应元素的前后元素引用
  • 在查找元素时,须遍历链表;在删除元素时,要遍历链表,找到要删除的元素,然后从链表上将元素删除即可
  • linkedList非线程安全的

ArrayList vs. LinkedList

很多教材上面都都有如下的推断: [1]. 如果使用的List结构中,有频繁的remove动作,而get动作较少,推荐使用LinkedList
[2]. 如果有大量的get动作,而remove动作较少,推荐使用ArrayList 那么这些推断都是正确的吗?

我们来测试一下ArrayList 和 LinkedList随机removey以及get的效率,数据量分别为 10000、30000、50000、100000

根据现象进行推理:
在随机执行remove的动作中,ArrayList的remove效率反而比LinkedList的效率高,是不是感觉很意外呢?为何会出现这种情况?理论上来说,LinkedList是基于链表的,删除只是需要修改一下指针的指向,而ArrayList是基于数组的,还有数组位置移动的时间代价,因而ArrayList的remove效率应该不如LinkedList

在随机执行get的动作中,ArrayList的get效率的确比LinkedList的效率高,原因是LinkedList每次执行get的时候,都是需要进行遍历寻找,这个耗时较为严重

BUT,请看下面的代码

// 在LinkedList执行删除的时候,会执行如下代码来寻找Node<E>,该Node对象中包含了实际你add的对象
public E remove(int index) {
 checkElementIndex(index);
 return unlink(node(index));
}
 
Node<E> node(int index) {
 // assert isElementIndex(index);
 if (index < (size >> 1)) {
 Node<E> x = first;
 for (int i = 0; i < index; i++)
 x = x.next;
 return x;
 } else {
 Node<E> x = last;
 for (int i = size - 1; i > index; i--)
 x = x.prev;
 return x;
 }
}

结论: LinkedList的remove操作,但就链表的指针指向动作,的确比ArrayList的数组拷贝要快速,但是LinkedList在node方法进行对象定位的过程中,时间损耗是很客观的

那么到底上述推断[1],是不是就完全不正确了呢?其实不然,如果List在顺序进行remove的时候,ArrayList的remove效率非常的糟糕,LinkedList的remove效率此时的优势就体现出来了,还是上面的代码 for (int i = 0; i < index; i++) 只需要遍历一次,就能定位到Node;如果是逆序进行remove,ArrayList 和 LinkedList在remove操作上的效率相差无几,ArrayList不用移动数组中的对象,LinkedList也只需要遍历一次就能定位到Node, for (int i = size - 1; i > index; i--)

get操作可以用上述方式进行推论

所以教科书上的东西,很多都是人云亦云,技术必须自己验证过,才放心使用。话有说回来,集合类的选用,应该追求实际的业务场景,追求一种平衡

Vector

  • Vector是基于Synchronized实现的线程安全的ArrayList,但在插入元素时容量扩充的机制和ArrayList稍有不同,并可通过传入capacityIncrement来控制容量的扩充(如果不传入capacityIncrement,则溢出时容量扩充为现有size的两倍)

Stack

  • Stack基于Vector实现,支持LIFO

HashSet

  • HashSet基于HashMap实现,无容量限制
  • HashSet是非线程安全的

TreeSet

  • TreeSet基于TreeMap实现,支持排序
  • TreeSet是非线程安全的

HashMap

HashMap非常的重要,要弄清楚它的实现原理
关键参数:
loadFactor,threshold,size=16 Entry[]
需要注意一下几点:

  • HashMap采用数组方式存储key、value构成的Entry对象,无容量限制
  • HashMap基于key hash寻找Entry对象存放到数组的位置,对于hash冲突采用链表的方式来解决
  • Hash在插入元素时,可能会要扩大数组的容量,在扩大容量时需要重新计算hash,并复制对象到新的数组中
  • HashMap是非线程安全的

TreeMap

是一个典型的机遇红黑树的实现,因此它要求一定要有key比较的方法,要么掺入Comparator,要么key对象实现Comparable接口
要点:

  • 基于红黑树实现,无容量限制
  • 是非线程安全的

工具类

Collections

需要掌握的api有: Collections.sort()
Collections.copy()
Collections.emptyXXX()
Collections.max()
Collections.min()

Arrays

Arrays.asList()
Arrays.sort()
Arrays.parallelSort()
Arrays.copyOf()

About

No description or website provided.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

AltStyle によって変換されたページ (->オリジナル) /