最近在准备面试,复习到集合类顺便整理一下,供以后查阅。
体系结构:
Collection
List
LinkedList
ArrayList
Vector
Stack
Set
HashSet
TreeSet
Map
Hashtable
HashMap
TreeMap
Collection是最基本的集合接口,一个Collection代表一组Object。
Collections类:Java.util.Collections是一个工具类,仅包含静态方法,它们操作或返回集合。
1.List 有序列表(可以有重复元素)
ArrayList 动态数组,它是以Array方式实现的List,允许快速随机存取。
LinkedList实现一个链表,提供最佳顺序存取,适合插入和移除元素。
Vector 类似ArrayList ,同步的,线程安全。
ArrayList和LinkedList的区别:
(1)ArrayList是由Array所支持的基于一个索引的数据结构,所以它提供对元素的随机访问,LinkedList存储一系列的节点数据,每个节点都与前一个和下一个节点相连接,所以ArrayList比LinkedList查询快。
(2)与ArrayList相比,在LinkedList中插入、添加和删除一个元素会更快,因为在一个元素被插入到中间的时候,不会涉及改变数组的大小,或更新索引。
(3)LinkedList比ArrayList消耗更多的内存,因为LinkedList中的每个节点存储了前后节点的引用。
ArrayList和Vector的不同点:
(1)Vector是同步的,而ArrayList不是。然而,如果你寻求在迭代的时候对列表进行改变,你应该使用CopyOnWriteArrayList。
(2)ArrayList比Vector快,它因为有同步,不会过载。
Array和ArrayList有何区别?什么时候更适合用Array?
(1)Array可以容纳基本类型和对象,而ArrayList只能容纳对象。
(2)Array是指定大小的,而ArrayList大小是固定的。
(3)Array没有提供ArrayList那么多功能,比如addAll、removeAll和iterator等。
适合用Array的场景:
(1)如果列表的大小已经指定,大部分情况下是存储和遍历它们。
(2)对于遍历基本数据类型,尽管Collections使用自动装箱来减轻编码任务,在指定大小的基本类型的列表上工作也会变得很慢。
(3)如果你要使用多维数组,使用[][]比List<List<>>更容易。
2.Set 集合(无序,不重复)
HashSet 能够快速定位一个元素,要注意的是:存入HashSet中的对象必须实现HashCode()方法;
TreeSet 将放入其中的元素按序存放。
3.Map 键值对(key不允许重复,值可以重复,无序)
HashMap 实现一个键到值映射的哈希表,通过get(key)来获取value,允许存储空对象,而且允许键是空(一个);
HashMap同步:Map m = Collections.synchronizedMap(hashMap);
HashTable 实现一个映象,所有的键必须非空。为了能高效的工作,定义键的类必须实现hashcode()方法和equal()方法。HashTable是同步的,线程安全的。
TreeMap,当元素以特定的顺序进行存储。
Properties 一般是把属性文件读入流中后,以键-值对的形式进行保存,以方便读取其中的数据。
HashMap和HashTable区别:
(1)HashMap允许key和value为null,而HashTable不允许。
(2)HashTable是同步的,而HashMap不是。所以HashMap适合单线程环境,HashTable适合多线程环境。
(3)在Java1.4中引入了LinkedHashMap,HashMap的一个子类,假如你想要遍历顺序,你很容易从HashMap转向LinkedHashMap,但是HashTable不是这样的,它的顺序是不可预知的。
(4)HashMap提供对key的Set进行遍历,因此它是fail-fast的,但HashTable提供对key的Enumeration进行遍历,它不支持fail-fast。
(5)HashTable被认为是个遗留的类,如果你寻求在迭代的时候修改Map,你应该使用CocurrentHashMap。
我们能否使用任何类作为Map的key
我们可以使用任何类作为Map的key,然而在使用它们之前,需要考虑以下几点:
(1)如果类重写了equals()方法,它也应该重写hashCode()方法。
(2)类的所有实例需要遵循与equals()和hashCode()相关的规则。
(3)如果一个类没有使用equals(),你不应该在hashCode()中使用它。
(4)用户自定义key类的最佳实践是使之为不可变的,这样,hashCode()值可以被缓存起来,拥有更好的性能。不可变的类也可以确保hashCode()和equals()在未来不会改变,这样就会解决与可变相关的问题了。所以String和Integer作为Map的key使用的比较多。
4.Iterator接口
Iterator接口位于java.util包中,它是一个对集合进行迭代的迭代器。
集合容器(如:List、Set、Map等)本身提供了处理元素置入和取出的方式,但是单一选取元素的方法很受限制。所以我们要用Iterator去选取容器中的元素,它将容器转换成一个序列。
Iterator iter=Object.iterator();
while(iter.hasNext()){ }
Iterater和ListIterator的区别:
(1)我们可以使用Iterator来遍历Set和List集合,而ListIterator只能遍历List。
(2)Iterator只可以向前遍历,而LIstIterator可以双向遍历。
(3)ListIterator从Iterator接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。
hashCode()和equals()方法的重要性:
HashMap使用Key对象的hashCode()和equals()方法去决定key-value对的索引。当我们试着从HashMap中获取值的时候,这些方法也会被用到。如果这些方法没有被正确地实现,在这种情况下,两个不同Key也许会产生相同的hashCode()和equals()输出,HashMap将会认为它们是相同的,然后覆盖它们,而非把它们存储到不同的地方。同样的,所有不允许存储重复数据的集合类都使用hashCode()和equals()去查找重复,所以正确实现它们非常重要。equals()和hashCode()的实现应该遵循以下规则:
(1)如果o1.equals(o2),那么o1.hashCode() == o2.hashCode()总是为true的。
(2)如果o1.hashCode() == o2.hashCode(),并不意味着o1.equals(o2)会为true。
与Java集合框架相关的使用经验:
(1)根据需要选择正确的集合类型。
(2)一些集合类允许指定初始容量,所以如果我们能够估计到存储元素的数量,我们可以使用它,就避免了重新哈希或大小调整。
(3)基于接口编程,而非基于实现编程。
(4)总是使用类型安全的泛型,避免在运行时出现ClassCastException。
(5)尽可能使用Collections工具类,或者获取只读、同步或空的集合,而非编写自己的实现。它将会提供代码重用性,它有着更好的稳定性和可维护性。
我们如何对一组对象进行排序?
对象数组,我们可以使用Arrays.sort()方法。
对象列表,我们可以使用Collections.sort()方法。
Collections内部使用数组排序方法,所有它们两者都有相同的性能,只是Collections需要花时间将列表转换为数组。
我们如何从给定集合那里创建一个synchronized的集合?
使用Collections.synchronizedCollection(Collection c)
根据指定集合来获取一个synchronized(线程安全的)集合。