持有对象

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lierming__/article/details/79903558

### Java 有多种方式保存对象(应该说是对象的引用)。

        ### Java  类库中提供了一套相当完整的容器:其中基本的

           类型是 List Set Queue Map 。这些对象的类型

           也称为集合类

》》泛型和类型安全的容器

       ###   ArrayList -->当作“可以自动扩充自身尺寸的数组”

             方法:add()    ---->加入元素

                         get(索引值)  ---->通过索引值来获取元素

                         size()   ----> 返回该容器中已经添加了多少元素

       ### class Apple {

                }

               class Orange{

               }

             不使用泛型的容器:

             ArrayList  apples = new ArrayList();

             apples.add(new Apple());

             apples.add(new Orange());

             说明:在以上不使用泛型的容器中,可以加入 Apple 类的

           对象的引用,还可以加入  Orange 类的对象的引用。这两个

           类都默认的继承 Object

               所以,加入的不同类的引用,在容器中都看做是  Object 类型。

           当从这样的容器中通过 get () 获取到元素时,要将 Object 类型

           强转 为  实际的类型,才能被正确的应用。

                如果不做上面的强转操作,那么会得到语法错误。

      ### 使用泛型:

                 要想定义用来保存 Apple 对象的 ArrayList ,你可以声明

           ArrayList<Apple>  ,而不仅仅只是 ArrayList , 其中尖括号

           括起来的是类型参数(可以有多个),它指定了这个容器实例

           可以保存的类型

                 通过使用泛型,就可以在编译期防止将错误类型的对象放置到

            容器中。

            --------------- 

            使用泛型的示例:

                ArrayList<Apple>  apples = new  ArrayList<Apple> ();

            --------------

           ### 通过使用泛型,你不仅知道编译器将会检查你放置到容器中

           的对象类型,而且在使用容器中的对象时,可以使用更加清晰的

          语法。(不需要进行类型强转,因为在加入之前就知道是什么类型的)

           ### 如果不需要使用每个元素的索引,你可以使用 foreach 语法来

           选择 List 中的每个元素。

            ### 当你指定了某个类型作为泛型参数时,你并不仅限于只能将

            该确切类型的对象放置到容器中。向上转型也可以像作用于其他类型

           一样作用于泛型。(即可以添加类型参数的导出类)

           ###通过使用  hashCode() 方法来产生散列码。

》》基本概念

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

                  概念:

             @@ Collection

                      一个独立元素的序列,这些元素都服从一条或多条规则。

                     List 必须按照插入的顺序保存元素;

                     Set 不能有重复的元素;

                     Queue 按照排队规则来确定对象产生的顺序(通常与它们被插

                            入的顺序相同)

             @@ Map 

                      一组成对的“键值对”对象,允许你使用键来查找值。

                     ArrayList  允许你使用数字来查找值,因此在某种意义上来说,它将

                数字与对象关联在了一起。

                     映射表允许我们使用另一个对象来查找某个对象,它也被称为“关联

                 数组

                     因此,你可以使用键对象来查找值对象

        ###  List <Apple>  apples = new  ArrayList<Apple>();   

                说明:ArrayList  已经向上转型为  List  类型了

                List 是一个接口。

        ### 在 Set 集合中,只有元素不存在的情况下才会添加。在使用 ArrayList 

               或者任何种类的 List 时,add( ) 方法总是表示“把它放进去”,因为在

               List 中不关心是否存在重复。

        ### 所有的 Collection 都可以用 foreach 语法遍历。

》》添加一组元素

        ###  Collection.addAll() 方法运行起来要快得多,而且构建一个不包含

               元素的 Collection  ,然后调用 Collections.addAll()这种方式很方便,

               因此它是首选方式。

        ### Collection.addAll()  成员方法只能接受另一个 Collection对象作为参数,

               因此它不如 Arrays.asList() 或 Collections.addAll() 灵活,这两个方法

                使用的都是可变参数列表。

        ###  如果你直接使用  Arrays.asList() 的输出,将其当作 List , 但是这种

             情况下,其底层表示的是数组因此不能调整尺寸。如果你试图

              add  () 或者 delete () 方法在这种列表中添加或删除元素,就有可能

             引发改变数组尺寸的尝试,因此你将在运行时获得“Unsupported(不支

             持的操作)”错误。

         ### 例如:

             List<Snow>  snow4 = Arrays.<Snow>asList();

              说明:可以在  Arrays.asList()  中间插入一条“线索”,以告知编译器

             对于由  Arrays.asList()  产生的 List 类型,实际的目标类型应该是什么,

             这称为显式类型参数说明

》》容器的打印

      ### 使用  Arrays.toString() 来产生数组的可打印表示,但是打印容器无需任何

              帮助。

      ### Java  容器类库中的两种主要类型:Collection  和   Map

              两者之间的区别因素:在于容器中每个“槽”保存的元素个数。

              @@ Collection 在每个槽中只能保存一个元素

                      List , 它以特定的顺序保存一组元素;

                      Set , 元素不能重复;

                      Queue , 只允许在容器一“端”插入对象,并从另一“端”

                                移除对象。

             @@ Map 在每个槽内保存了两个对象,即和与之相关联的

       ### Collection  打印出来的内容用方括号括住,每个元素由逗号隔开;

                例如:  [rat , cat , dog]

                Map 打印出来的内容用大括号括住,键与值由等号联系(键在左,值在右)

               例如:  { 键1 =值1 , 键2=值2 , 键3=值3}

      ###   ArrayList  和 LinkedList  都是  List 类型的。从输入可以看出,它们都

               按照被插入的顺序保存元素。两者之间的不同之处不仅仅在于执行某些

               类型的操作时的性能,而且  LinkedList  包含的 操作多于 ArrayList 。

       ### HashSet  、TreeSet 和 LinkedSet  都是  Set 类型,每个相同的项

               只有保存一次,但是输出也显示了不同的 Set 实现存储元素的方式也

               不同

                HashSet : 是最快的获取元素方式。

                TreeSet  : 偏向于存储顺序很重要,它按照比较结果的升序保存对象。

                LinkedSet : 按照被添加的顺序保存对象。

       ###  Map (也被称为关联数组):使得你可以用来查找对象。

               补充:对于每一个键,Map 只接受存储一次。

       ### Map.put(key,value) 方法将增加一个值,并将它与某个键关联起来。

               Map.get(key) 方法将产生与这个键相关联的值。

                注意:你不必考虑  Map 的尺寸,因为它自己会自动地调整尺寸。

        ### 键和值在 Map 中的保存顺序并不是它们的插入顺序,因为  HashMap 

                实现使用的是一种非常快的算法来控制顺序。

        ###  Map :  HashMap   、TreeMap  和 LinkedHashMap

                HashMap : 提供了最快的查找技术,也没有按照任何明显的顺序来保存

                                     其元素;

                TreeMap : 按照比较结果的升序保存键;

                LinkedHashMap : 按照插入顺序来保存键,同时还保留了  HashMap 的

                                    查找速度       

》》List

          ### List 接口在 Collection 的基础上添加了大量的方法,使得可以在 List 的

                中间插入和移除元素。

         ### 有两种类型的 List  :

                  @@  基本的 ArrayList , 它长于随机访问元素,但是在 List 的中间插入和

                       移除元素慢

                  @@ LinkedList ,它通过代价较低的在 List 中间进行 的插入和删除操作,

                      提供了优化的顺序访问。LinkedList  在随机访问方面相对比较慢,但是

                      它的特性集较 ArrayList 更大 。 

         ### 与数组不同,List 允许在它被创建之后添加元素、移除元素,或者自我

                 调整尺寸。这正是它的重要价值所在:一种可修改的序列。

         ### 对于其他的类, equals () 的定义可能有所不同。例如,两个

                 String  只有在内容完全相同的情况下才是等价的。

         ### 对于 LinkedList  ,在列表中间插入和删除都是廉价的操作,但是对于

                  ArrayList 是代价高昂的操作。

         ### 优化是一个很棘手的问题,最好的策略就是置之不顾,直到你发现需要

                 担心它了(尽管理解这些问题总是一种好的思路)

》》迭代器 

         ### 任何容器类,都必须有某种方式可以插入元素并将它们再次返回。毕竟,

                 持有事物是容器最基本的工作。对于 List , add( ) 是插入元素的方法之一,

                而  get( ) 是取出元素的方法之一。

        ### 迭代器(也是以一种设计模式)是一个对象,它的工作是遍历并选择序列

               中的对象,而客户端程序员不必知道或关心该序列底层的结构。

        ### 迭代器通常被称为轻量级对象:创建它的代价小。因此,经常可以见到

                对迭代器有些奇怪的限制;

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

                          (1)、使用方法 iterator() 要求容器返回一个  Iterator 。Iterator 将

                             准备好返回序列的第一个元素

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

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

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

          ### 有了 Iterator 就不必为容器中元素的数量操心了,那是由 hasNext( ) 

                  和 next( ) 关心的事情了。

          ### 如果你只是向前遍历  List ,并不打算修改 List 对象本身,那么你可以

                  看到 foreach 语法显得更加简洁。

          ### Iterator 还可以移除由 next( ) 产生的最后一个元素,这意味着在调用

                  remove( ) 之前必须先调用 next ( ) 

          ### Iterator 能够将遍历序列的操作与序列底层的结构分离。正由于此,

                 我们有时会说:迭代器统一了对容器的访问方式。

      ----- ListIterator

           ### ListIterator 是一个更加强大的  Iterator 的子类型,它只能用于各种

                    List 类的访问。尽管 Iterator 只能向前移动,但是 ListIrerator 可以

                  双向移动。它还可以产生相对于迭代器在列表中指向的当前位置和

                 前一个和后一个元素的索引,并且可以使用 set( ) 方法替换它访问过

                 的最后一个元素。

          ### 你可以通过调用  listIterator () 方法产生一个指向 List  开始处的

                ListIterator , 并且还可以通过调用 listIterator (n) 方法创建一个一开始

                就指向列表索引为  n 的元素处 ListIterator  。

》》LinkedList

         ### LinkedList 也像  ArrayList 一样实现了基本的  List 接口,但是它执行

                某些操作(在 List 的中间插入和移除)时比 ArrayList 更高效,但在

                随机访问操作方面却要逊色一些。

         ### LinkedList 还添加了可以是用作队列双端队列的方法。

        ### getFirst( ) 和  element( ) 完全一样,它们都返回元素列表的头(第一个

                元素),而并不移除它,如果 List 为空,则抛出 NoSuchElement :

                Exception 。

                peek( ) 方法与这两个方式只是有些差异,它在列表为空时返回 null 。 

         ### removeFirst() 与 remove()  也是完全一样的,它们移除并返回列表的头,

               而在列表为空时抛出 NoSuchElementException  。

               poll ( ) 稍有些差异,它在列表为空时返回 null 。

         ### addFirst( ) 与 add( ) 和 addLast( ) 相同,它们都将某个元素插入到列表

              的尾(端)部。

         ### removeLast( ) 移除并将返回列表的最后一个元素。

        ### Queue   接口是在  LinkedList 的基础上添加了 element( ) 、offer () 、

              peek( ) 、poll( ) 和 remove() 方法,以使其成为一个 Queue 的实现。

》》Stack

         ### “栈”通常是指“后进先出”(LIFO)的容器。有时栈也被成为叠加栈

               因为最后“压入”栈的元素,第一个“弹出”栈。经常用来类比栈的事物

               是装有弹簧的储放器中的自助餐托盘,最后装入的托盘总是最先拿出的。

         ### LinkedList 具有能够直接实现栈的所有功能的方法,因此可以直接将

               LinkedList 作为栈使用。不过,有时一个真正的“栈”更能把事情讲清楚。

        ### 将 LinkedList 看作一个  栈(Stack) 来使用:

                peek( ) 方法将提供栈顶元素,但是不将其从栈顶移除;

                poll( ) 将其移除并返回栈顶元素

》》Set

         ### Set 不保存重复的元素。如果你试图将相同对象的多个实例添加到

                  Set 中,那么它就会阻止这种重复现象。

         ### Set 中最常使用的是测试归属性,你可以很容易地询问某个对象是否在

                 某个 Set 中。正因为如此,查找就成了 Set 中最重要的操作,因此你

                 通常都会选择一个 HashSet 的实现,它专门对快速查找进行了优化。

          ###  Set 具有与 Collection 完全一样的接口,因此没有任何额外的功能。

          ### 实际上 Set 就是 Collection ,只是行为不同。

          ### Set 是基于对象的值来确定归属性的。

          ### HashSet 所维护的顺序与 TreeSet LinkedHashSet  都不同,因为

                  它们的实现具有不同的元素存储方式。

                   @@ TreeSet 将元素存储在 红-- 黑树数据结构中

                   @@ HashSet 使用的是散列函数

                   @@LinkedHashSet 因为查询速度的原因也使用了散列,但是看起来

                           使用了链表来维护元素的插入顺序

         ###如果你想对结果排序,一种方式是使用  TreeSet 来代替 HashSet 。

》》Map

         ### 将对象映射到其他对象的能力是一种解决编程问题的杀手锏。

         ### Map 与数组和其他的 Collection  一样,可以很容易地扩展到多维,而

                 我们只需要将其值设置为 Map (这些 Map 的值可以是其他容器,甚至

                 是其他 Map )。因此,我们能够很容易地将容器组合起来从而快速地

                 生成强大的数据结构。

                 假如:你正在跟踪拥有多个宠物的人,你所需只是一个

                              Map<Person , List<Pet>>

          ### Map 可以返回它的键的 Set ,它的值的 Collection ,或者它的键值对的

                 Set 。

》》Queue

         ### 队列是典型的先进先出(FIFO)的容器。即从容器的一端放入事物,从另

               一端取出,并且事物放入容器的顺序与取出的顺序是相同的。队列常被当作

               一种可靠的将对象从程序的某一个区域传输到另一个区域的途径。队列在并发

              编程中特别重要,因为它可以安全地将对象从一个任务传输给另一个任务

       ###  LinkedList  提供了方法以支持队列的行为,并且它实现了 Queue 接口,因此

             LinkedList 可以用作 Queue 的一种实现。

       ###  注意,与 Queue 相关的方法提供了完整而独立的功能。即,对于 Queue 所继承

            的 Collection , 在不需要使用它的任何方法的情况下,就可以有一个可用的

           Queue

     ----- PriorityQueue (优先级队列)

        ### 先进先出描述了最典型的队列规则。先进先出声明的是下一个元素应该是等待时间

            最长的元素。

        ### 优先级队列声明下一个弹出元素是最需要的元素(具有最高的优先级)。

        ### Integer 、 String 和 Character  可以与 PriorityQueue 一起工作,因为这些类已经

              内建了自然排序。如果你想在 PriorityQueue 中使用自己的类,就必须包括额外的

              功能以产生自然排序,或者必须提供自己的 Comparator 。

》》Collection 和 Iterator

         ### Collection 是描述所有序列容器的共性的根接口,它可能会被认为是一个“附属接口”,

               即因为要表示其他若干个接口的共性而出现的接口。另外,java.util.AbstractColletion

               类提供了 Collection 的默认实现,使得你可以创建  AbstractCollection 的子类型,而

                其中没有必要的代码重复。

         ### 使用接口描述的一个理由是它可以使我们能够创建更通用的代码。通过针对接口而非

               具体的实现来编写代码,我们的代码可以应用于更多的对象类型。

         ###  实现 Collection 就意味着需要提供 iterator() 方法。

         ###   生成 Iterator 是将队列与消费队列的方法连接在一起耦合度最小的方式,并且与实现

                 Collection 相比,它在序列类上所施加的约束也少得多。

》》Foreach 与迭代器

         ### 到目前为止,foreach 语法主要用于数组,但是它也可以应用于任何 Collection 对象。

         ###  不存在任何从数组到 Iterator 的自动转换,你必须手工执行转换。

     ------ 适配器方法惯用法

         ### ”适配器“来自于设计模式。

》》总结

         ###  数组将数字与对象联系起来。它保存类型明确的对象,查询对象时,不需要对结果做

              类型转换。它可以是多维的,可以保存基本类型的数据。但是,数组一旦生成,其容量

             就不能改变。

        ###  Collection  保存单一的元素,而 Map 保存相关联的键值对。有了 Java 的泛型,你就

             可以指定容器中存放的对象类型,因此你就不会将错误类型的对象放置到容器中,并且

              在容器中获取元素时,不必进行类型转换。各种 Collection  和各种 Map 都可以在你向

           其中添加元素时,自动调整其尺寸。容器不能持有基本类型,但是自动包装机制会仔细地

            执行基本类型到容器中所持有的包装器类型之间的双向转换。

        ###  像数组一样,List 也建立数字索引与对象的关联,因此,数组和 List 都是排好序的容器。

             List 能够自动扩充容量。

        ###  如果要进行大量的随机访问,就使用 ArrayList  ; 如果要经常从表中间插入或删除元素,

             则应该使用 LinkedList

        ### 各种 Queue 以及栈的行为,由 LinkedList 提供支持。

        ###   Map 是一种将对象(而非数字)与对象相关联的设计。HashMap 设计用来快速访问;

             而 TreeMap 保持 ” 建 “ 始终处于排序状态,所有没有  HashMap  快。LinkedHashMap

             保持元素插入的顺序,但是也通过散列提供了快速访问能力。

        ###  Set 不接受重复的元素。HashSet 提供最快的查询速度,而 TreeSet 保持元素处于排序

            状态。 LinkedHashSet 以插入顺序保存元素。

        ###  新程序中不应该使用过时的 Vector 、 Hashtable 和 Stack

        ###  简单的容器分类图:(如下)

           

            说明:(1)、从上图中可以看出,只有四种容器:Map 、 List 、 Set 、 Queue 。

                        它们各有两到三个实现版本。常用的容器用黑色粗线线框(黄色背景)表示

                      (2)、点线框表示接口,实现框表示普通的(具体的)类。

                      (3)、带有空心箭头的点线表示一个特定的类实现一个接口;

                                 实心箭头表示可以生成箭头所指向类的对象。

                      (4)、除了 TreeSet 之外的所有 Set 都拥有与 Collection 完全一样的接口。

                      (5)、List 和 Collection  存在着明显的不同,尽管 List 所要求的方法都在

                                 Collection 中。

                      (6)、在 Queue 接口中的方法都是独立的,在创建具有 Queue 功能的实

                                现时 不需要使用 Collection 方法。

                      (7)、Map 和 Collection  之间唯一重叠就是 Map 可以使用 entrySet ( )

                                和 values ( ) 方法来产生 Collection

               补充:(1)、标记接口 java.util.RandomAccess 附着到了  ArrayList 上,而没有

                         附着到 LinkedList 上。这为想要根据所使用的特定的 List 而动态修改其行为

                        的算法提供了信息。

猜你喜欢

转载自blog.csdn.net/lierming__/article/details/79903558