JavaSE(六) 集合框架1

1.Java 集合框架

(1)集合的接口与实现分离
Java 接口类库将接口(interface)和实现(implementation)分离。当程序中使用集合框架时,一旦构建后就不需要知道究竟使用了哪种实现。因此,只有在构建集合对象时,使用具体的类才有意义。使用接口类型存放集合的引用:

Queue<Customer> q = new CircularArryQueue<>(100);
q.add(new Customer("Harry"));

接口本身不能说明哪种实现的效率究竟如何。

(2) Collection 接口

public interface Collection<E>{
	boolean add(E element);//添加元素改变了集合返回 true,否则 false;
	Iterator<E> iterator();
	...
}

(3) 迭代器

public interface Iterator<E>{
	E next();
	boolean hasNext();
	void remove();
	default void forEachRemaining(Consumer<? super E> action);// java 8;

}

next() 方法可以逐个访问集合中的元素,到达集合的末尾,将抛出一个 NoSuchElementException,因此在调用 next() 方法前需要调用 hasNext() 方法。

Collection<String> c = ...;
Iterator<String> iter = new c.iterator();
for(String element : c) {   // for each循环可以与任何实现了 Iterator 接口的对象一起工作;
	do somethig with element; 
}

Collection 接口拓展了 Iterator 接口,因此标准类库中的任何集合都可以使用 ”for each“ 循环。
在 JavaSE 8 中,可以调用 forEachRemaining 方法并提供一个 lambda 表达式:

iterator。forEachRemaining(element -> do something with element);

元素被访问的顺序取决于集合类型,对 ArrayList 进行迭代,迭代器将从索引开始,每迭代一次索引 +1 。对于 HashSet ,访问的次序随机,无法预知,但是每个元素都会被访问。
迭代器的查找操作与位置变更是紧密相连的,调用 next(),迭代器就会越过下一个元素,并返回刚刚越过的那个元素的引用:
在这里插入图片描述

remov() 方法则会删除调用 next 方法时返回的元素,如果调用 remove() 前没用调用 next 将是不合法的。若果这样做将抛出一个 IllegalStateException 异常。

it.remove();
it.next();
it.remove;

(4) 泛型的实用方法

int size();
boolean isEmpty();
boolean contains(Object obj);
.... //祥查 jdk 文档

如果实现 Collection 接口的每一个类都需要提供如此多的例行方法会很麻烦。Java 提供了 AbstractCollection,它将基础方法 size 和 iterator 抽象化了,但是在此提供了例行方法。此时一个具体的集合类可以拓展 AbstractCollection 类,由具体的集合类提供 iterator 方法,而 contains 方法已经由 AbstractCollection 超类提供了。

(5)集合框架中的接口
在这里插入图片描述
Collection 和 Map 是集合框架中两个基本接口;
List 是一个有序集合,元素会增加到容器中的特定位置,可以使用迭代器(顺序访问)或者整数索引(random access)来访问元素。
ListIterator 接口 是 Iterator 的一个子接口,它定义了一个方法用于在迭代器位置前面增加一个元素:

void add(E element);

Set 等同于 Collectin 接口,不过其方法有更严谨的定义,set 的 add 方法不允许添加重复的元素。set 的 equals 方法:只要两个集包含同样的元素就认为是相等的,而不要去元素有同样的顺序,hashcode() 方法的定义要保证包含相同元素的两个 Set 会得到相同的散列码(hashcode);

2.具体的集合类

在这里插入图片描述

(1) List
<1> LinkedList
LinkedList 实际上是双向链接的,即每个节点还存放着指向前驱节点的引用。
LinkedList 与泛型集合的一个重要区别为:LinkedList 是一个有序集合,LinkedList.add 将对象添加到链表的尾部。如果希望将元素添加到链表的中间,可以使用迭代器实现。Iterator 的子接口 ListIterator 中包含 add 方法(有序集合中使用迭代器添加元素才有实际意义),这个方法不会返回 boolean。ListIterator 还有两个方法可以用来反向遍历链表:

E previous();
boolean hasPervious();

ListIterator 的 set 方法可以用来用一个新元素取代调用 next 或 previous 方法返回的上一个元素。
为了多个迭代器修改同一个集合会抛出 ConcurrenModificationException 异常,可以给容器添加多个可以读取列表的迭代器,另外,再附加一个既能读又能写的迭代器。
避免使用整数索引表示链表中位置的所有方法。如果需要对集合进行随机访问,就使用数组或 ArrayList。

<2>ArrayList
ArrayList 封装了一个动态再分配的对象数组。
为什么使用 ArrayList 取代 Vector:
Vector 类所有方法都是同步的,但是如果一个线程访问 Vector,代码要在同步操作上花费大量时间,而 ArrayList 是不同步的,因此,建议再不需要同步时使用 ArrayList。

(2) Set
hash table:快速查找所有所需要对象的数据结构。hash table 为每一个对象计算一个 hash code(注意,自己实现的 hashCode 方法应该与 equals 方法兼容,即 a.eaquals(b) 为 true,则 a 和 b 必须具有相同的 hash code)。
hash table 在 Java 中的实现:
在 Java 中,hash table 由链表数组实现,每个列表被称为桶 (bucket)。想要查找表中对象的位置,就要计算它的 hash code,然后与 bucket 的总数取余,所得到的结果就是保存这个元素桶的索引。如果桶中没有其他元素,则将元素直接插入,若桶被占满则被称为散列冲突(hash collision),这时需要用新对象与 bucket 中所有对象进行比较。一般将 bucket 的数量设置为预计元素个数的 75%-150%,最好为素数。装填因子(load factor) 决定了何时对散列表进行再散列 (rehashed,创建一个 bucket 更多的表),装填因子 0.75 比较合适,即表中 75% 的位置已经填入元素,表就会用双倍的 bucket 进行再散列。
Set:Set 是没有重复元素的元素的集合,Set 的 add 方法首先在 Set 中查找要添加的对象,若不存在,即添加。
<1> HashSet
HashSet 实现了基于 hash table 的 Set,可以用 add 添加元素,重写的 contains 方法用来查看某个元素是否出现在 Set 中,但是只会在某个 bucket 中查找,不必查看 Set 中所有元素。
如果元素的 hash code 发生改变,则元素在数据结构中的位置也会发生改变。
<2> TreeSet
TreeSet 是一个有序集合,可以以任意顺序插入元素,遍历时,元素会自动按照红黑树排序后的顺序呈现。
将元素添加到树中比添加到 hashtable 中要慢,但是比检查数组或链表中的重复元素要快。
虽然 添加一个元素,treeset 比 hashset 花费的时间并不多太多,但是,不需要对元素进行排序,就没有必要付出排序的开销。
<3>Queue
Queue 可以有效的在尾部添加一个元素,在头部删除一个元素(先进先出),但不支持在队列中间添加元素。
priority queue (优先级队列)可以按照任意顺序插入,却总是按照排序的顺序进行检索。也就是说 remove 方法总会获得当前优先级队列中的最小的元素。但是优先级队列并没有对所有元素进行排序,其依靠的是——堆(heap),堆是个可以自我调整的二叉树,对树执行 add 和 remove ,可以让最小的元素移动到根。

3. Map

Map 是用来存放键值对的(key/value),如果提供键就能查到值。
<1> HashMap
HashMap 对键进行散列。基本 Map 操作:

Map<String,Employee> staff = new HashMap<>();
Employee harry = new Employee("HarryNice");
staff.put("001",harry);
String id = "001";
e = staff.get(id);//如果没有默认

迭代处理 Map:

scores.forEach(k,v) -> System.out.pringln(k,v);

<2>TreeSet
TreeSet用键的整体顺序对元素进行排序,并将其组织成搜索树。

<3>Map 试图
集合框架不认为 Map 本身是一个集合,不过可以得到 Map 的视图(View)——实现了 Collection 接口或某个子接口的对象。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值