复习 Core Java Chap13 Collections 笔记

- 13.1.1 

Java 将 interfaces 于 implementations 分离。

例如 Queue 是一个 interface。通常有两种实现方法: circular array, linked list, 分别对应 ArrayDeque 类 和 LinkedList 类。 从实现上看,circular array 比 linked list 更高效,但是容量有限。选择 linked list 则对象数量没有上限。利用接口类型去存放对象:

Queue<Customer> expressLaneArray = new ArrayDeque<Customer>(100);
Queue<Customer> expressLaneLL = new LinkedList<Customer>();

这样做的好处是,可以轻松地改为另一种不同的实现。

Java 中也有以 Abstract 开头的集合类,例如 AbstractQueue。这是为类库的实现者设计的。我们也可以通过 extends 这些 Abstract 集合类来实现自己的集合类。


- 13.1.2

Collection 是最基本的集合类接口。它包含2个基本的方法:

public interface Collection<E> {
	boolean add(E element);
	Iterator<E> iterator();
}

iterator(迭代器) 方法用于返回一个实现了 Iterator 接口的对象。Iterator 接口包含3个方法:

public interface Iterator<E> {
	E next();
	boolean hasNext();
	void remove();
}

next() 可以逐个访问集合中的每个元素,但若到了集合末尾,则会抛出 NoSuchElementException. 因此在调用 next 之前要调用 hasNext() :

Collection<String> c = ...
Iterator<String> iter = c.iterator();
while (iter.hasNext()) {
	String element = iter.next();
	...
}

也可以用 for each 的写法遍历集合:

for (String element : c) {
	...
}

for each 写法可以与任何实现了 Iterable 接口的对象工作。Iterable 接口:

public interface Iterable<E> {
	Iterator<E> Iterator();
}

Collection 接口 extends Iterable 接口,由上面我们也知道 Collection 接口包含 Iterator<E> Iterator() 方法。 所以 for each 写法对标准库的任何集合都成立。

对于 Iterator 迭代访问的顺序是基于不同的集合类型而定的。例如 ArrayList 的迭代,从index 0 开始,递增。对于 HashSet 的迭代是随机的,无法预知元素出现的次序。如果想按照特定的顺序,可以用 TreeSet 或者 LinkedHashSet.

 删除元素,ierator.remove() 将会删除上次调用 next() 时返回的元素。因为从逻辑上,删除一个元素前先看一下它是什么是符合意义的。所以应该先调用next(), 返回了这个元素,知道它是什么,才决定去 remove. 实际上,调用 remove 前必须调用 next, 否则不合法:

Iterator<String> iter = c.iterator();
iter.next(); // skip over the first element
iter.remove(); // delete the first element

Iterator<String> iter = c.iterator();
iter.remove(); // call remove without next, error

Iterator<String> iter = c.iterator();
iter.next();
iter.remove();
iter.next();
iter.remove(); // work


13.2.1 链表

在 Java 中的LinkedList 类是双向的 (doubly linked list).

若使用 LinkedList 类的 add 方法,就是像链表的尾部添加一个元素。如果想向链表中间的某个位置添加元素,就要依赖于 iterator 的 add 方法。但是只有对有序的集合使用 Iterator 的 add 才有意义。例如 Set 中的元素本身就是无序的,那么使用 iterator 的 add 是没有意义不合逻辑的。因此, Iterator 这个接口是没有 add 方法的。 ListIterator 才有 add 方法。 因为 List 是双向的(例如 LinkedList), 所以 ListIterator 也提供向前遍历,所以有:

E previous();
boolean hasPrevious();

与 next() 和 hasNext() 对应。

ListIterator 的 add 方法是在 迭代器位置之前添加一个新元素。可以这样看待:

 | ABC

A | BC

AB | C

ABC |

这里回顾一下迭代器的 remove 方法。remove 是删掉了迭代器刚刚越过 (skip over)的元素。如果是使用 next,则删掉了迭代器左侧的元素,但是若使用 previous, 则删掉了迭代器右侧的元素。

关于迭代器的 set 方法。set 是将一个新元素取代 next 或 previous 方法返回的上一个元素(也就是刚越过的元素):

ListIterator<String> iter = list.listIterator();
String old = iter.next();
iter.set(new); // set the first to a new value

最后是多个迭代器访问一个集合产生的问题。假设一个迭代器修改集合,另外一个对其遍历。遍历的那个迭代器指向一个元素前面,这个元素却被负责修改的迭代器删除了,那么遍历的迭代器就是无效的:

List<String> list = ...
ListIterator<String> iter1 = list.listIterator();
ListIterator<String> iter2 = list.listIterator(); // at this point, iter1 and iter2 both at begining
iter1.next();
iter1.remove(); // first element is removed by iter1
iter2.next; // ConcurrentModificationException here

另外需要注意的是,linkedlist 的 index access 复杂度是 O(n)。所以 list.get(n) 的效率很低,下面是一个效率极低的访问链表的代码:

for (int i = 0; i < list.size(); i++) {
	list.get(i)...
}


13.2.3 HashSet

13.2.4 TreeSet

TreeSet 是有序的,底部使用红黑树实现。添加的过程比 HashSet 要慢。


13.2.8 HashMap

HashMap 本身不属于 Collection,但是可以用下面3个 Collection 来表达:

Set<K> keySet();

Collection<V> values();

Set<Map.Entry<K, V> > entrySet();

Set<String> keys = map.keySet();
for (String key : keys) {
	...
}

for (Map.Entry<String, Employee> entry : staff.entrySet) {
	String key = entry.getKey();
	Employee value = entry.getValue();
}


13.3.3 集合和数组转换

Set<String> ts = new HashSet<String>();
ts.add("Ammy");
ts.add("Bob");
ts.add("Carl");
		
String[] arr = ts.toArray(new String[0]);
for (int i = 0; i < arr.length; i++) {
	System.out.println(arr[i]);
}


		String[] arr = new String[3];
		arr[0] = "Ammy";
		arr[1] = "Bob";
		arr[2] = "Carl";
		
		Set<String> set = new HashSet<String>(Arrays.asList(arr));
		Iterator<String> iter = set.iterator();
		while (iter.hasNext()) {
			System.out.println(iter.next());
		}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值