Set和Map的关系:
- Set集合由无序的不可重复元素构成,Map集合由多个键值对构成。
- Set 和 Map均为接口,其的具体Set 实现类的底层依赖于Map的实现类,用实现Map接口集合类来储存具体的元素。
- Set具体实现类所储存的元素和一个Object对象,构成键值对,储存于依赖的Map中。
Map的实现若干细节:
- Map的实现集合类储存元素在一个Entry对象数组中,Entry对象中包含键值对.假如存在相同hashcode的Entry对象,该Entry对象还包含一个另一个Entry对象的引用。
- 实现了Map接口的HashMap中一个Entry对象数组中元素储存位置一般由键名的hashcode作为参数,调用indexFor方法决定位置,即该Entry对象储存在数组中的索引。
- 假如出现相同hashcode的键名,这找到已存在Entry对象数组中同键名hashcode的元素,把新加入的Entry对象添加该数组位置上,把该Entry中的一个Entry引用变量指向到由与该元素相同的hashcode的其他所有元素构成的链表开头那个元素中去。
- HashMap中有一个负载因子,决定储存数据的Entry对象数组的满载程度,默认为0.75,该值决定什么时候该增大Entry对象数组的容量。增大数组时,使用数组复制方法System.arraycopy,会消耗系统资源。
- 要实现有序的集合Set或Map,要覆写元素对象的hashCode和equals方法,保证相同内容的对象的这两方法返回值相同。
- TreeMap总是有序的,因为采用红黑树的数据结构来储存元素Entry,父节点总是大于左子节点,小于右子节点。
List的实现若干细节:
- 主要实现类有ArrayList和LinkedList,两者区别于前者储存元素用数组,后者用双向链表。
- ArrayList为线程不安全,Vector为线程安全,实现与前者相似,都是用数组来做储存数据。如需要使用线程安全的List,不推荐使用Vector,建议用Collections.synchronizedList方法即可将普通的ArrayList包装成线程安全。
- ArrayList和Vector在扩充储存数组的方式不同,前者扩充为原来的1.5倍,后者增长固定大小。
- 选择ArrayList还是LinkedList,取决于实际对数据的操作。如插入、删除方法使用频繁,则使用LinkedList,因为这仅仅是节点引用的改变。而ArrayList则要向后移动数组元素,为新增的元素腾出位置。
- Stack为Vector子类,增加5个方法,都是线程安全的。Java不推荐使用,而是采用jdk1.6新增的Deque接口的实现类ArrayDeque,该类实现了双端队列的功能,既可以作为栈FILO,又可以作为队列FIFO。
集合的迭代器:
- 使用foreach语句的集合必须实现Iterator接口;
- 除了EnumSet集合的Iterator是RegularEnumSet的一个内部类,所有Set集合对应的Iterator都是与它对应的Map类的内部类KeyIterator。
- 在迭代集合时直接删除集合中某个元素时,会抛出ConcurrentModificationException异常。但在删除倒数第二个元素时不会出现异常,原因在于hasNext方法。该方法实现就一句return cursor != size(),则删除了倒数第二个元素后该方法就会返回fasle,就不会在调用next方法获得下个元素。
- next方法内调用方法checkForComodification(),该方法内部实现为:
- 删除一个集合内的元素,在迭代过程中,不要直接对集合进行删除操作,应该调用该集合的迭代器的remove()方法进行删除操作。