Java Collections框架中包含了大量集合接口以及这些接口的实现类和操作它们的算法(例如排序、查找、反转、替换、复制、取最小元素、去最大元素),主要提供了List(列表)、Queue(队列)、Set(集合)、Stack(栈)和Map(映射表,用于存放键值对)等数据结构。其中,List、Queue、Set、Stack都继承自Collection接口。
- Set表示数学意义上的集合概念。其最主要的特点是集合中的元素不能重复,一次存入Set的每个元素都必须定义equals()方法来确保对象的唯一性。该接口有两个实现类:HashSet和TreeSet。TreeSet实现了SortedSet接口,因此TreeSet容器中的元素是有序的。
- List又称为有序的Collection。它按对象进入的顺序保存对象,所以它能对列表中的每个的插入和删除位置进行精确的控制,同时可以保存重复的对象。LinkedList、ArrayList和Vector都实现了List接口。
- Map提供了一个从键映射到值得数据结构。它用于保存键值对,其中值可以重复,但是键是唯一的,不能重复。Java类库中有多个实现该接口的类:HashMap、TreeMap、LinkedHashMap、WeakHashMap和IdentityHashMap。HashMap是基于散列表实现的,采用对象的HashCode可以进行快速查询。LinkedHashMap是采用列表来维护内部顺序。TreeMap基于红黑树的数据结构来实现的,内部元素是按需排列的。
迭代器(Iterator)
迭代器(Iterator)是一个对象,它的工作室遍历并选择序列中的对象,它提供了一种访问一个容器(container)对象的各个元素,而又不必暴露该对象内部细节的方法。通过迭代器,开发人员不需要了解容器底层的结构,就可以实现对容器的遍历。
迭代器的是由主要有以下3个方面注意事项:
- 使用容器的iterator()方法返回一个Iterator,然后通过Iterator的next()方法返回第一个元素。
- 使用Iterator的hasNext()方法判断容器是否还有元素,如果有,可以使用next()方法获取下一个元素。
- 可以通过remove()方法删除迭代器返回的元素。
示例:
public class IteratorTest{
public static void main(String []args){
List<String> ll = new LinkedList<String>();
ll.add("first");
ll.add("second");
ll.add("third");
for(Iterator<String> iter = ll.iterator();iter.hasNext();){
String str = iter.next();
System.out.println(str);
}
}
}
注:
- 单线程中,在遍历的过程中把需要删除的对象保存到一个集合中,等遍历结束后调用removeAll()方法来删除,或者使用iter.remove()方法。
- 使用ConcurrentHashMap和CopyOnWriteArrayList等线程安全的容器来代替非线程安全的容器。
- 在使用迭代器遍历容器时对容器的操作放到synchronized代码块中,但是当引用程序并发程度高时,这会严重影响程序的性能。
ArrayList、Vector和LinkedList的区别
- ArrayList和Vector都是基于存储元素的Object[] array来实现的,它们在内存中开辟一块连续的空间来存储,由于数据存储室连续的,因此,它们支持用序号(下标)来访问元素,同时索引数据的速度比较快。但是在插入元素时需要移动容器中的元素,所以对数据的插入操作执行比较慢。当它们的容量所存储的元素超过这个大小时就需要动态地扩充它们的存储空间。它们的区别是synchroonization(同步)的使用,没有一个ArrayList的方法是同步的,而Vector的绝大多数方法(add、insert、remove、set、equals、hascode等)都是直接或间接同步的,所以Vector是线程安全的,ArrayList不是线程安全的。
- LinkedList是采用双向列表来实现的,对数据的索引需要从列表头开始遍历,因此用于随机访问则效率比较低,但是插入元素时不需要对数据进行移动,因此插入的效率高,是非线程安全的容器。
- 当对数据的主要操作是索引或志在集合的末端增加、删除元素时,使用ArrayList和Vector效率比较高;当对数据的操作主要为指定位置的插入和删除操作时,使用LinkedList效率比较高;当在多线程中使用容器时(即多个线程会同时访问该容器),选用Vector较为安全。
HashMap、HashTable、TreeMap和WeakHashMap区别
Map是用来存储键值对的数据结构,通过对象进行索引,用来索引的对象叫做key,其对应的对象叫做value。
Hash是一个最常用的Map,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问数据。区别:
- HashMap是HashTable的轻量级实现(非线程安全),HashMap允许一条记录的键值(key)为空(null),HashTable不允许。
- HashMap把HashTable的contains方法去掉了,改成containsvalue和containsvalueKey。
- HashTable的方法是线程安全的,HashMap不支持线程的同步,所以不是线程安全的。在多线程访问HashTable时,不需要开发人员对它进行同步,而对于HashMap,需要提供额外的同步机制。
- HashTable使用Enumeration,HashMap使用Iterator。
- hash值得使用不同,HashTable直接使用对象的hashCode。
HashMap里面存入的键值对取出时没有固定顺序,随机的。在Map中插入、删除和定位元素,HashMap是最好的选择。由于TreeMap实现了SortMap接口,能够把它保存的记录根据根据键排序,取出来是排序后的键值对,如果需要按自然顺序或自定义顺序遍历键,使用TreeMap。
WeakHashMap与HashMap类似,二者不同之处在于WeakHashMap中的key采用的是“弱引用”的方式,只要WeakHashMap中的key不再被外部引用,它就可以被垃圾回收器回收。而HashMap中key采用的是“强引用的方式”,当HashMap中的key没有被外部引用时,只有在这个key从HashMap中删除后,才可以被垃圾回收器回收。
注:
- 在HashMap上下文中,同步意味着在一个时间点只能有一个线程可以修改hash表,任何线程在执行HashTable的更新操作前都需要获取对象锁,其他线程则等待锁的释放。
- HashMap可以通过Map m = Collections.synchronizedMap(new HashMap())来达到同步的效果。即,该方法返回一个同步的Map,该Map封住了底层的HashMap的所有方法,使得底层的HashMap即使是在多线程的环境中也是安全的。
网友评论