集合类操作优化经验总结(二)

…衆ロ難τιáo~ 提交于 2020-03-06 18:20:54

集合类介绍

LinkedList 类

LinkedList 实现了 List 接口,允许 Null 元素。此外 LinkedList 提供额外的 Get、Remove、Insert 等方法在 LinkedList 的首部或尾部操作数据。这些操作使得 LinkedList 可被用作堆栈(Stack)、队列(Queue)或双向队列(Deque)。请注意 LinkedList 没有同步方法,它不是线程同步的,即如果多个线程同时访问一个 List,则必须自己实现访问同步。一种解决方法是在创建 List 时构造一个同步的 List,方法如

List list = Collections.synchronizedList(new LinkedList(...));

ArrayList 类

ArrayList 实现了可变大小的数组。它允许所有元素,包括 Null。Size、IsEmpty、Get、Set 等方法的运行时间为常数,但是 Add 方法开销为分摊的常数,添加 N 个元素需要 O(N) 的时间,其他的方法运行时间为线性。

每 个 ArrayList 实例都有一个容量(Capacity),用于存储元素的数组的大小,这个容量可随着不断添加新元素而自动增加。当需要插入大量元素时,在插入前可以调用 ensureCapacity 方法来增加 ArrayList 的容量以提高插入效率。和 LinkedList 一样,ArrayList 也是线程非同步的(unsynchronized)。

ArrayList 提供的主要方法:

  1. Boolean add(Object o) 将指定元素添加到列表的末尾;

  2. Boolean add(int index,Object element) 在列表中指定位置加入指定元素;

  3. Boolean addAll(Collection c) 将指定集合添加到列表末尾;

  4. Boolean addAll(int index,Collection c) 在列表中指定位置加入指定集合;

  5. Boolean clear() 删除列表中所有元素;

  6. Boolean clone() 返回该列表实例的一个拷贝;

  7. Boolean contains(Object o) 判断列表中是否包含元素;

  8. Boolean ensureCapacity(int m) 增加列表的容量,如果必须,该列表能够容纳 m 个元素;

  9. Object get(int index) 返回列表中指定位置的元素;

  10. Int indexOf(Object elem) 在列表中查找指定元素的下标;

  11. Int size() 返回当前列表的元素个数。

Vector 类

Vector 非常类似于 ArrayList,区别是 Vector 是线程同步的。由 Vector 创建的 Iterator,虽然和 ArrayList 创建的 Iterator 是同一接口,但是,因为 Vector 是同步的,当一个 Iterator 被创建而且正在被使用,另一个线程改变了 Vector 的状态(例如,添加或删除了一些元素),这时调用 Iterator 的方法时将抛出 ConcurrentModificationException,因此必须捕获该异常。

Stack 类

Stack 继承自 Vector,实现了一个后进先出的堆栈。Stack 提供 5 个额外的方法使得 Vector 得以被当作堆栈使用。除了基本的 Push 和 Pop 方法,还有 Peek 方法得到栈顶的元素,Empty 方法测试堆栈是否为空,Search 方法检测一个元素在堆栈中的位置。注意,Stack 刚创建后是空栈。

Set 类

Set 是一种不包含重复的元素的 Collection,即任意的两个元素 e1 和 e2 都有 e1.equals(e2)=false。Set 最多有一个 null 元素。很明显,Set 的构造函数有一个约束条件,传入的 Collection 参数不能包含重复的元素。请注意,必须小心操作可变对象(Mutable Object),如果一个 Set 中的可变元素改变了自身状态,这可能会导致一些问题。

Hashtable 类

Hashtable 继承 Map 接口,实现了一个基于 Key-Value 映射的哈希表。任何非空(non-null)的对象都可作为 Key 或者 Value。添加数据使用 Put(Key,Value),取出数据使用 Get(Key),这两个基本操作的时间开销为常数。

Hashtable 通过 Initial Capacity 和 Load Factor 两个参数调整性能。通常缺省的 Load Factor 0.75 较好地实现了时间和空间的均衡。增大 Load Factor 可以节省空间但相应的查找时间将增大,会影响像 Get 和 Put 这样的操作。使用 Hashtable 的简单示例,将 1、2、3 这三个数字放到 Hashtable 里面,他们的 Key 分别是”one”、”two”、”three”,代码如清单 2 所示。

清单 2 .Hashtable 示例
Hashtable numbers = new Hashtable();
numbers.put(“one”, new Integer(1));
numbers.put(“two”, new Integer(2));
numbers.put(“three”, new Integer(3));

如果我们需要取出一个数,比如 2,可以用相应的 key 来取出,代码如清单 3 所示。

清单 3.从 Hastable 读取数据
Integer n = (Integer)numbers.get(“two”); 
System.out.println(“two =”+ n);

由于作为 Key 的对象将通过计算其散列函数来确定与之对应的 Value 的位置,因此任何作为 key 的对象都必须实现 HashCode 和 Equals 方法。HashCode 和 Equals 方法继承自根类 Object,如果你用自定义的类当作 Key 的话,要相当小心,按照散列函数的定义,如果两个对象相同,即 obj1.equals(obj2)=true,则它们的 HashCode 必须相同,但如果两个对象不同,则它们的 HashCode 不一定不同,如果两个不同对象的 HashCode 相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的 HashCode() 方法,能加快哈希表的操作。

如果相同的对象有不同的 HashCode,对哈希表的操作会出现意想不到的结果(期待的 Get 方法返回 Null),要避免这种问题,最好同时复写 Equals 方法和 HashCode 方法,而不要只写其中一个。

HashMap 类

HashMap 和 Hashtable 类似,不同之处在于 HashMap 是线程非同步的,并且允许 Null,即 Null Value 和 Null Key。但是将 HashMap 视为 Collection 时(values() 方法可返回 Collection),其迭代子操作时间开销和 HashMap 的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将 HashMap 的初始化容量设得过高,或者 Load Factor 参数设置过低。

WeakHashMap 类

WeakHashMap 是一种改进的 HashMap,它对 Key 实行“弱引用”,如果一个 Key 不再被外部所引用,那么该 Key 可以被 GC 回收。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!