Java编程思想-容器

通常,程序总是根据运行时才知道的某些条件去创建新对象。在此之前,不会知道所需对象的数量,甚至不知道确切的类型。为解决这个普遍的编程问题,需要在任意时刻和任意位置创建任意数量的对象。

Java有多种保存对象(应该说是对象的引用)。数组是保存一组对象的最有效的方式,但是数组具有固定的尺寸,而在更一般的情况中,你写程序并不知到需要多少个对象,或者是否需要更复杂的方式来存储对象,因此数组尺寸这一限制显得过于受限了。

Java实用类库提供了一套相当完整的容易类来解决这个问题,其中基本的类型是List、Set、Queue和Map。即使在Java中没有直接的关键字支持,容器类仍然是可以显著增强你的编程能力的基本工具。

11.1 泛型和类型安全的容器

要想定义用来保存Apple对象的ArrayList,你可以声明ArrayList <Apple>
,而不仅仅只是ArrayList,其中尖括号括起来的是类型参数(可以有多个),它指定了这个容器实例可以保存的类型。通过使用泛型,就可以在编译期防止将错误类型的对象放置到容器中。

11.2 基本概念

Java容器类类库的用途是“保存对象”,并将其划分为两个不同的概念:

1)Collection。一个独立元素的序列,这些元素都服从一条或多条规则。List必须按照插入的顺序保存元素,而Set不能有重复元素。Queue按照排队规则来确定对象产生的顺序(通常与它们被插入的顺序相同)。

2)Map。一组成对的“键值对”对象,允许你使用键来查找值。ArrayList允许你使用数字来查找值,因此在某种意义上讲,它将数字与对象关联在了一起。映射表允许我们使用另一个对象来查找某个对象,它也被称为“关联数组”,因为它将某些对象与另外一些对象关联在了一起;或者被称为“字典”,因为你可以使用键对象来查找值对象,就像在字典中使用单词来定义一样。

11.3 添加一组元素

在java.util包中的Arrays和Collections类中都有很多实用方法,可以在一个Collection中添加一组元素。Arrays.asList()接受一个数组或是一个逗号分隔的元素列表(使用可变参数),并将其转换为一个List对象。Collections.addAll()方法接受一个Collection对象,以及一个数组或者一个用逗号分隔的列表,将元素添加到Collection中。

下面例子展示了这两个方法:

public class AddingGroup {
    public static void main(String[] args) {
        Collection<Integer> collection = new ArrayList<Integer>(Array.asList(1,2,3,4,5,));
        Integer[] moreInts = {6,7,8,9,10};
        collection.addAll(Arrays.asList(moreInts));
        
        Collections.addAll(collection,11,12,13,14,15);
    }
}

Collection.addAll()成员方法只能接受另一个Collection对象作为参数,因此它不如Collections.addAll()灵活,后一个使用的是可变参数列表。

11.4 容器的打印

你必须使用Arrays.toString()来产生数组的可打印表示,但大音容器无需任何帮助。

public class PrintingContainers {
    static Collection fill(Collection<String> collection) {
        collection.add("cat");
        collection.add("dog");
        return collection;
    }
    public static void main(String[] args) {
        print(fill(new ArrayList<String>()));
    }
}/*
[cat, dog]
*/

如果存储顺序很重要,那么就可以使用TreeSet,它按照比较结果的升序保存对象;或者使用LinkedHashSet,它按照被添加的顺序保存对象。

11.5 List

有两种类型的List:

  • 基本的ArrayList,它长于随机访问元素,但是在List的中间插入和移除元素时较慢。
  • LinkedList,它通过代价较低的在List中间进行的插入和删除操作,提供了优化的顺序访问。

你可以使用contains()方法来确定某个对象是否在列表中。如果你想移除一个对象,则可以将这个对象的引用传递给remove()方法。

当确定一个元素是否属于某个List,发现某个元素的索引,以及从某个List中移除一个元素时,都会用到equals()方法。

11.6 迭代器

任何容器类,都必须有某种方式可以插入元素并将它们再次取回。毕竟,持有事务是容器最基本的工作。对于List,add()是插入元素的方法之一,而get()是取出元素的方法之一。

如果打算编写通用的代码,它们只是使用容器,不知道或者不关心容器的类型,那么如何才能不重写代码就可以应用于不同类型的容器?

迭代器(也是一种设计模式)可以达成此目的。迭代器是一个对象,它的工作是遍历并选择序列中的对象,而程序员不必知道或者关心该序列底层的结构。

Java的Iterator只能单向移动,这个Iterator只能用来:

1)使用方法iterator()要求容器返回一个Iterator。Iterator将准备好返回序列的第一个元素

2)使用next()获得序列中的下一个元素。

3)使用hasNext()检查序列中是否还有元素。

4)使用remove()将迭代器新近返回的元素删除。

11.6.1 ListIterator

ListIterator是一个更加强大的Iterator的子类型,它只能用于各种List类的访问。尽管Iterator只能向前移动,但是ListIterator可以双向移动。

11.8 Stack

LinkedList具有能够直接实现栈的所有功能的方法,因此可以直接将LinkedList作为栈使用。下面是代码示例:

public class Stack<T> {
    private LinkedList<T> storge = new LinkedList<T>();
    public void push(T v) { storge.addFirst(v); }
    public T peek() { return storge.getFirst();}
    public T pop() { return storage.removeFirst(); }
    public boolean empty() { return storge.isEmpty(); }
    public String toString() { return storge.toString(); }
}

11.9 Set

Set不保存重复的元素。Set中最常被使用的是测试归属性,你可以很容易地询问某个对象是否在某个Set中。正因如此,查找就成为了Set中最重要的操作,因此你通常都会选择一个HashSet的实现,它专门对快速查找进行了优化。

TreeSet将元素存储在红-黑树数据结构中,而HashSet使用的是散列函数。LinkedHashList因为查询速度的原因也使用了散列,但是看起来它使用了链表来维护元素的插入顺序。

11.11 Queue

LinkedList提供了方法以支持队列的行为,并且它实现了Queue接口,因此LinkedList可以看作Queue的一种实现。

11.11.1 PriorityQueue

先进先出描述了最典型的队列规则。队列规则是指在给定一组队列中的元素的情况下,确定下一个弹出队列的元素的规则。先进先出声明的是下一个元素应该是等待时间最长的元素。

11.14 总结

Java提供了大量持有对象的方式:

1)数组将数字与对象关联起来。它保存类型明确的对象,查询对象时,不需要对结果做类型转换。但是,数组一旦生成,其容量就不能改变。

2)Collection保存单一的元素,而Map保存相关联的键值对。有了Java的泛型,你就可以指定容器中存放的对象类型。各种Collection和各种Map都可以在你向其中添加更多的元素时,自动调整其尺寸。容器不能持有基本类型,但是自动包装机制会仔细地执行基本类型到容器中所持有的包装器类型之间的双向转换。

3)Map是一种将对象(而非数字)与对象相关联的设计。HashMap设计用来快速访问;而TreeMap保持"键"始终处于排序状态,所以没有HashMap快。LinkedHashMap保持元素插入的顺序,但是也通过散列提供了快速访问能力。

4)简单的容器分类
yFVu11.png
你可以看到,其实只有四种容器:Map、List、Set和Queue,它们各有两到三个实现版本。常用的容器用黑色粗线框表示。

点线框表示接口,实现框表示普通的类。带有空心箭头的点线表示一个特定的类实现了一个接口,实心箭头表示某个类可以生成箭头所指向类的对象。

参考:

  • 《Java编程思想》
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值