1.数组 有两方面的问题将数组与其他集合类型区分开来: 效率和 类型。对于 Java 来说, 为保存和访问一系列对象 (实际是对象的句柄)数组,最有效的方法莫过于数组。数组实际代表一个简单的线性序列,它使得元素的 访问速度非常快,但我们却要为这种速度付出代价: 创建一个数组对象时,它的大小是固定的,而且不可在 那个数组对象的“存在时间”内发生改变。 无论使用的数组属于什么类型,数组标识符实际都是指向真实对象的一个句柄。那些对象本身是在内存 “堆”里创建的。堆对象既可“隐式”创建(即默认产生),亦可“显式”创建(即明确指定,用一个 new 表达式)。堆对象的一部分(实际是我们能访问的唯一字段或方法)是只读的length(长度)成员,它告诉 我们那个数组对象里最多能容纳多少元素。对于数组对象,“ []”语法是我们能采用的唯一另类访问方法。 集合类只能容纳对象句柄。但对一个数组,却既可令其直接容纳基本类型的数据,亦可容纳指向对象的句 柄。
2.集合 Java 提供了四种类型的“ 集合类”: Vector(矢量)、 BitSet(位集)、 Stack(堆栈)以及 Hashtable(散列表)。 新的集合库考虑到了“容纳自己对象”的问题,并将其分割成两个明确的概念: (1) 集合( Collection): 一组单独的元素,通常应用了某种规则。在这里,一个 List(列表)必须按特定 的顺序容纳元素,而一个 Set(集)不可包含任何重复的元素。相反,“包”( Bag) 的概念未在新的集合库 中实现,因为“列表”已提供了类似的功能。
(2) 映射(Map):一系列“键-值”对(这已在散列表身上得到了充分的体现)。从表面看,这似乎应该成 为一个“键-值”对的“集合”,但假若试图按那种方式实现它,就会发现实现过程相当笨拙。这进一步证 明了应该分离成单独的概念。另一方面,可以方便地查看 Map 的某个部分。只需创建一个集合,然后用它表 示那一部分即可。这样一来, Map 就可以返回自己键的一个 Set、一个包含自己值的 List 或者包含自己“键 -值”对的一个 List。和数组相似, Map 可方便扩充到多个“维”,毋需涉及任何新概念。只需简单地在一 个 Map 里包含其他 Map(后者又可以包含更多的 Map,以此类推)
集合示意图:
这张图刚开始的时候可能让人有点儿摸不着头脑,但在通读了本章以后,相信大家会真正理解它实际只有三 个集合组件: Map, List 和 Set。而且每个组件实际只有两、三种实现方式,而且通常都只有一种 特别好的方式。只要看出了这一点,集合就不会再令人生畏。 虚线框代表“接口”, 点线框代表“抽象”类,而 实线框代表普通(实际)类。 点线箭头表示一个特定的类 准备实现一个接口(在抽象类的情况下,则是“部分”实现一个接口)。 双线箭头表示一个类可生成箭头指 向的那个类的对象。
3.集合的缺点 :类型未知 使用 Java 集合的“缺点” 是在将对象置入一个集合时丢失了类型信息。之所以会发生这种情况,是由于当初 编写集合时,那个集合的程序员根本不知道用户到底想把什么类型置入集合。若指示某个集合只允许特定的 类型,会妨碍它成为一个“常规用途”的工具,为用户带来麻烦。为解决这个问题,集合实际容纳的是类型 为 Object 的一些对象的句柄。这种类型当然代表 Java 中的所有对象,因为它是所有类的根。
4.枚举器(反复器) 它可以是一个对象,作用是遍历一系列对象,并选择 那个序列中的每个对象,同时不让客户程序员知道或关注那个序列的基础结构。此外,我们通常认为反复器 是一种“轻量级”对象;也就是说,创建它只需付出极少的代价。但也正是由于这个原因,我们常发现反复 器存在一些似乎很奇怪的限制。例如,有些反复器只能朝一个方向移动。 Java 的 Enumeration(枚举)便是具有这些限制的一个反复器的例子。除下面这些外,不可再用它 做其他任何事情: (1) 用一个名为 elements()的方法要求集合为我们提供一个 Enumeration。我们首次调用它的 nextElement() 时,这个 Enumeration 会返回序列中的第一个元素。 (2) 用 nextElement() 获得下一个对象。 (3) 用 hasMoreElements()检查序列中是否还有更多的对象。
5.BitSet BitSet 实际是由“ 二进制位”构成的一个 Vector。如果希望高效率地保存大量“开-关”信息,就应使用 BitSet。它只有从尺寸的角度看才有意义;如果希望的高效率的访问,那么它的速度会比使用一些固有类型 的数组慢一些。 此外, BitSet 的最小长度是一个长整数( Long)的长度: 64 位。这意味着假如我们准备保存比这更小的数 据,如 8 位数据,那么 BitSet 就显得浪费了。所以最好创建自己的类,用它容纳自己的标志位。 在一个普通的 Vector 中,随我们加入越来越多的元素,集合也会自我膨胀。在某种程度上, BitSet 也不例 外。
6.Stack Stack 有时也可以称为“后入先出”( LIFO)集合。换言之,我们在堆栈里最后“压入”的东西将是以后第 一个“弹出”的。和其他所有 Java 集合一样,我们压入和弹出的都是“对象”,所以必须对自己弹出的东西 进行“造型”。
7.使用接口代替一个具体实现类的好处 List x = new LinkedList(); 当然,也可以决定将 x 作为一个 LinkedList 使用(而不是一个普通的 List),并用 x 负载准确的类型信 息。 使用接口的好处就是一旦决定改变自己的实施细节,要做的全部事情就是在创建的时候改变它,就象下 面这样: List x = new ArrayList(); 其余代码可以保持原封不动
8.List接口 List(接口) 顺序是 List 最重要的特性; 它可保证元素按照规定的顺序排列。 List 为 Collection 添加了 大量方法,以便我们在 List 中部插入和删除元素(只推荐对 LinkedList 这样做)。 List 也会生成一个 ListIterator(列表反复器),利用它可在一个列表里朝两个方向遍历,同时插入和删除位于列表中部的元 素(同样地,只建议对 LinkedList 这样做) ArrayList* 由一个数组后推得到的 List。作为一个常规用途的对象容器使用,用于替换原先的 Vector。允 许我们快速访问元素,但在从列表中部插入和删除元素时,速度却嫌稍慢。 一般只应该用ListIterator 对一 个 ArrayList 进行向前和向后遍历,不要用它删除和插入元素;与 LinkedList 相比,它的效率要低许多 LinkedList 提供优化的顺序访问性能,同时可以高效率地在列表中部进行插入和删除操作。但在进行随机访 问时,速度却相当慢,此时应换用 ArrayList。也提供了 addFirst(), addLast(), getFirst(), getLast(), removeFirst() 以及 removeLast()(未在任何接口或基础类中定义),以便将其作为一个规格、 队列以及一个双向队列使用
9.Set接口 Set 拥有与 Collection 完全相同的接口,所以和两种不同的 List 不同,它没有什么额外的功能。相反, Set 完全就是一个 Collection,只是具有不同的行为(这是实例和多形性最理想的应用:用于表达不同的行 为)。在这里,一个 Set 只允许每个对象存在一个实例. Set(接口) 添加到 Set 的每个元素都必须是独一无二的;否则 Set 就不会添加重复的元素。添加到 Set 里 的对象必须定义 equals(),从而建立对象的唯一性。Set 拥有与 Collection 完全相同的接口。一个 Set 不能 保证自己可按任何特定的顺序维持自己的元素
10.Map Map(接口) 维持“键-值”对应关系(对),以便通过一个键查找相应的值 HashMap* 基于一个 散列表实现(用它代替 Hashtable)。针对“键-值”对的插入和检索,这种形式具有 最稳定的性能。可通过构建器对这一性能进行调整,以便设置散列表的“能力”和“装载因子” ArrayMap 由 一个 ArrayList 后推得到的 Map。对 反复的顺序提供了精确的控制。面向非常小的 Map 设计,特别是那些需要经常创建和删除的。对于非常小的Map,创建和反复所付出的代价要比 HashMap 低得多。但在 Map 变大以后,性能也会相应地大幅度降低 TreeMap 在一个“红-黑”树的基础上实现。查看键或者“键-值”对时,它们会按固定的顺序排列。 TreeMap 最大的好处就是我们得到的是已排好序的结果。 TreeMap 是含有 subMap()方法的唯一一种 Map,利用它可以返回树的一部分
最近在看JAVA编程思想(第四版)这本书,将书中的一些知识点容易遇到或者混淆的概念记录下来,只是作为备忘,希望也能帮到需要的人,特此申明.