Java核心技术:集合——Java集合框架


Java最初版本只为最常用的数据结构提供了很少一组类:Vector、Stack、Hashtable、BitSet与Enumeration接口,其中的Enumeration接口提供了一种用于访问任意容器中各个元素的抽象机制。
Java SE 1.2之后,设计人员退出了一组功能更加完善的数据结构。

将集合的接口与实现分离

Java集合类库将接口(interface)与实现(implementation)分离。下面以队列(queue)进行举例说明。
队列结构指出了队列可以进行的操作,队列接口的最简形式可能类似下面这样:

public interface Queue<E> // a simplified from of the interface in the standard library
{
	void add(E element);
	E remove();
	int size();
}

队列通常有两种实现方式:一种使用循环数组;另一种使用链表。

public class CircularArrayQueue<E> implements Queue<E> // not an actual library class
{
	private int head;
	private int tail;

	CircularArrayQueue(int capacity) { ... }
	public void add(E element) { ... }
	public E remove() { ... }
	public int size() { ... }
	private E[] elements;
}
public class LinkedListQueue<E> implements Queue<E> // not an actual library class
{
	private Link head;
	private Link tail;

	LinkedListQueue() { ... }
	public void add(E element) { ... }
	public E remove() { ... }
	public int size() { ... }
}

注释:Java类库并没有这两个类。这里,只是作为示例。
当在程序中使用队列时,一旦集合构建后就不需要知道究竟使用了哪种实现。因此,只有在构建集合对象时,使用具体的类才有意义。可以使用接口类型存放集合的引用

Queue<Customer> expressLane = new CircularArrayQueue<>(100);
expressLane.add(new Customer("Harray"));

利用这种方式,一旦改变了想法,可以轻松地使用另一种不同的实现。只需要对程序调用构建的地方做出修改。如果觉得LinkedListQueue是个更好的选择,就将代码修改为:

Queue<Customer> expressLane = new LinkedListQueue<>();
expressLane.add(new Customer("Harray"));

在研究API文档时,会发现另一组名字已Absract开头的类,例如,AbstractQueue。这些类是为类库实现着而设计的。扩展这些类要比实现接口中的所有方法轻松得多。

Collection接口

在Java类库中,集合类的基本接口是Collection接口。

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

迭代器

Iteratro接口包含4个方法:

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

通过反复调用next方法,可以逐个访问集合中的每个元素。但是,如果到达了集合的末尾,next方法将抛出一个NoSuchElementException。因此,需要在调用next之前调用hasNext方法。如果迭代器对象还有多个供访问的元素,这个方法就返回true。

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

用“for each”循环可以更加简练。

for (String element : c)
{
	do something with element
}

编译器简单地将“for each”循环翻译为带有迭代器的循环
“for each”循环可以与任何实现了Iterable接口的对象一起工作,这个接口只包含一个抽象方法:

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

Collection接口扩展了Iterable接口。对于标准类库的任何集合都可以用"for each"循环。
在Java SE 8中,甚至不用写循环。可以调用forEachRemaining方法并提供一个lambda表达式。将对迭代器的每一个元素调用这个lambda表达式,知道再没有元素为止。

iterator.forEachRemaining(elment -> do something with element);

应该将Java迭代器认为是位于两个元素之间。当调用next时,迭代器就越过下一个元素,并返回刚刚越过的那个元素的引用。
迭代器
可以将Iterator.nextInputStream.read看作为等效的。
Iterator接口的remove方法将会删除上次调用next方法时返回的元素。如果要删除指定位置上的元素,仍然需要越过这个元素。

Iterator<String> it = c.iterator();
it.next();
it.remove();

对next方法和remove方法的调用具有互相依赖性。如果调用remove之前没有调用next将是不合法的。不然,会抛出一个IllegalStateException异常。

泛型使用方法

Collection与Iterator都是泛型接口,可以编写操作任何集合类型的方法。
Collection接口声明了很多有用的方法。所有的实现类都必须提供这些方法。

int size()
boolean isEmpty()
boolean contains(Object obj)
boolean equals((Object obj)
boolean addAll(Collection<? extends E> from)
boolean remove(Object obj)
boolean removeAll(Collection<?> c)
void clear()
boolean retainAll(Collection<?> c)
Object[] toArray()
<T> T[] toArray(T[] arrayToFill)

为了能够让实现者更容易地实现这个接口,Java类库提供了一个类AbstractCollection,一个具体的集合类可以扩展AbstractCollection类,AbstractCollection抽象了size和iterator方法。
Collection
Iterator

集合框架中的接口

集合框架中的接口
集合有两个基本接口:Collection和Map
List是一个有序集合(ordered collection)。支持使用迭代器访问或者使用一个整数索引访问。
由数组支持的有序集合可以快速地随机访问,链表也是有序的,但随机访问很慢,最好用迭代器来遍历。Java的集合框架并没有使用不同的接口进行区分,为了避免对链表完成随机访问操作,Java SE 1.4引入了一个标记接口RandomAccess。这个接口不包含任何方法,不过可以用来测试一个特定的集合是否支持高效的随机访问:

if (c instanceof RandomAccess)
{
	use random access algorithm
}
else
{
	use sequential access algorithm
}

Set接口等同于Collection,不过add方法不允许增加重复的元素。要适当定义集(set)的equals方法:只要两个集包含同样的元素就认为是相等的,而不要求这些元素有同样的顺序。hashCode方法的定义要保证包含相同元素的两个集会得到相同的散列码。
SortedSet和SortedMap接口会提供用于排序的比较器对象。
Java SE 6引入了接口NavigableSet和NavigableMap,包含一些用于搜索和遍历有序集合映射的方法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值