Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 270|回复: 0

[集合学习]定制与扩展Java集合框架

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-30 23:55:49 | 显示全部楼层 |阅读模式
    这是Ted NewardIBM developerWorks5 things系列文章中的一篇,讲述了关于java集合框架的一些应用窍门,值得大家学习。(2010.05.02最后更新)

         概要:Java集合API远不止是数组的替代品,尽管那是一个不坏的认知起点。Ted Neward展示了5个能更大利用集合框架的窍门,包含一个定制并扩展Java集合API的入门级应用。

         对于许多Java开发者而言,Java集合API是标准的Java数组及其全部缺点的必要替代品。将集合框架主要与ArrayList联系起来并不是一个错误,但集合框架中还有许多需要关注的地方。
         同样地,尽管对于名-值或键-值对来说,Map(及其它的常选实现HashMap)是极好的,但仍没理由把自己限制在这些熟悉的工具中。你可使用正确的 API,甚至是正确的集合API去修正许多存在潜在错误的代码。  
      
       
       
         
       

         
       
      


         本文是5 things系列的第二篇文章,也是针对集合框架若干篇文章中的第一篇,因为在我们进行Java编程时,集合框架处于核心地位。开始时,将会看到处理常见工作,例如将Array转换成List,的便捷(但并不是最通用的)方法。之后,我们将深入研究集合框架中不太常见的主题,例如扩展Java集合框架API并定制一个集合类.

    1. 使用集合对象处理数组
         新接触Java技术的开发者可能不知道数组是天然包含在Java语言中的,这是为了应对上世纪九十年代早期来自于C++开发者们有关性能的批评。是的,从那以后,我们已经历了很长时间,当与Java集合类库相比较时,数组的性能优势正在变小。
         例如,将数组中的内容导出成一个字符串时,需要遍历数组,然后将其中的内容连接成一个String类型;然而,集合框架的实现都有其各自不同的 toString实现。
    除了极少数情况,一种好的实践方式就是尽快将任何数组转换成集合对象。这就提出了一个问题,有什么最简单的方法来做这种转换呢?事实证明,Java集合框架API使这一过程变得简单,如清单1所示:

    清单1. ArrayToList
      
      
       
      import
       java.util.
      *
      ;


      public
       
      class
       ArrayToList
    {
         
      public
       
      static
       
      void
       main(String[] args)
         {
             
      //
       This gives us nothing good
      

              System.out.println(args);
             
             
      //
       Convert args to a List of String
      

              List
      <
      String
      >
       argList
      =
       Arrays.asList(args);
             
             
      //
       Print them out
      

              System.out.println(argList);
         }
    }
      

    注意,返回的List是不可修改的,所以当试图向其中添加新的元素时,将会抛出UnsupportedOperationException。
         因为Arrays.asList方法对添加到List中的元素使用vararg(可变长参数),你就可使用它轻松地创建被新建对象的List对象。

    2. 迭代的效率不高
         将一个集合对象(特别是该集合是由一数组转化而成的)中的内容移入到另一个集合对象,或是从一个较大对象集合中删除一个较小的对象集合,这些都是不常见的需求。
         你可能会尝试着迭代该集合,然后向其中添加或删除每一个被找到的元素,但不能这样做。
         在这个例子中,迭代有很大的缺点:

       
       在每一次添加或删除动作之后,无法高效地重新调整集合的大小。
       为了进行这些操作,在获取和释放锁时会有潜在的并发性梦魇。
       当正在进行添加或删除元素时,其它线程也在操作你的集合,这就会导致竞争条件。  
       针对你想添加或删除元素的集合对象,使用addAll或removeAll方法,你就能避免上述所有问题。

    3. 利用for循环遍历Iterable对象

         在Java 5中加入的最好的Java语言便捷特性之一,改进的for循环,消除了操作Java集合对象的最后一道障碍。
         在此之前,开发者们必须得手工地获取Iterator,使用next()方法去获得Iterator中被指定的对象,以及通过hasNext()方法来检查是否还有更多的对象。在Java 5之后,我们可以方便地使用for-loop变体来默默地处理上述所有操作。
         准确地说,这种改进并不仅仅针对集合对象,而可用于任何实现了Iterable接口的对象。
         清单2展示了如何将Person对象中的children作为一个Iterator去制成一个列表。不同于操作一个指向内部List的引用(这会允许 Person的外部调用者向你的家庭中添加新的子女--大多数父母会对此感到不快的),Person类型实现了Iterable接口。该方法也能使改进的 for循环可遍历其中的孩子列表。

    清单2. 改进的for循环:列出你的子女
      
      
       
      //
       Person.java
      

      import
       java.util.
      *
      ;


      public
       
      class
       Person
         
      implements
       Iterable
      <
      Person
      >
      
    {
         
      public
       Person(String fn, String ln,
      int
       a, Person... kids)
         {
             
      this
      .firstName
      =
       fn;
      this
      .lastName
      =
       ln;
      this
      .age
      =
       a;
             
      for
       (Person child : kids)
                 children.add(child);
         }
         
      public
       String getFirstName() {
      return
       
      this
      .firstName; }
         
      public
       String getLastName() {
      return
       
      this
      .lastName; }
         
      public
       
      int
       getAge() {
      return
       
      this
      .age; }
         
         
      public
       Iterator
      <
      Person
      >
       iterator() {
      return
       children.iterator(); }
         
         
      public
       
      void
       setFirstName(String value) {
      this
      .firstName
      =
       value; }
         
      public
       
      void
       setLastName(String value) {
      this
      .lastName
      =
       value; }
         
      public
       
      void
       setAge(
      int
       value) {
      this
      .age
      =
       value; }
         
         
      public
       String toString() {
             
      return
       
      "
      [Person:
      "
       
      +
      
                
      "
      firstName=
      "
       
      +
       firstName
      +
       
      "
       
      "
       
      +
      
                
      "
      lastName=
      "
       
      +
       lastName
      +
       
      "
       
      "
       
      +
      
                
      "
      age=
      "
       
      +
       age
      +
       
      "
      ]
      "
      ;
         }
         
         
      private
       String firstName;
         
      private
       String lastName;
         
      private
       
      int
       age;
         
      private
       List
      <
      Person
      >
       children
      =
       
      new
       ArrayList
      <
      Person
      >
      ();
    }


      //
       App.java
      

      public
       
      class
       App
    {
         
      public
       
      static
       
      void
       main(String[] args)
         {
             Person ted
      =
       
      new
       Person(
      "
      Ted
      "
      ,
      "
      Neward
      "
      ,
      39
      ,
                
      new
       Person(
      "
      Michael
      "
      ,
      "
      Neward
      "
      ,
      16
      ),
                
      new
       Person(
      "
      Matthew
      "
      ,
      "
      Neward
      "
      ,
      10
      ));

             
      //
       Iterate over the kids
      

             
      for
       (Person kid : ted)
             {
                 System.out.println(kid.getFirstName());
             }
         }
    }
      

    对于域模型,使用Iterable接口会有一些明显的缺点,因为只有一个对象集合能够通过iterator()方法得到如此"隐式"的支持。在这种情况下,children集合在何处是确定且透明的,然而,Iterable接口可使程序设计在应对域类型时要容易得多,也会更明显。

    4. 典型的及定制的算法
         你曾经会想过遍历一个集合对象,但是从相反的方向呢?这就是典型的Java集合框架算法用得上的地方。
         上述清单2中Person的子女以他们被添加的顺序来排列的;但现在你希望以相反的顺序列出这些子女。当你编写另一个for循环,以相反的顺序向各个对象添加到一个新的ArrayList中时,代码在编写了第三或第四遍之后将变得冗长。
         清单3就是未被利用的算法:

    清单3. ReverseIterator
      
      
       
      public
       
      class
       ReverseIterator
    {
         
      public
       
      static
       
      void
       main(String[] args)
         {
             Person ted
      =
       
      new
       Person(
      "
      Ted
      "
      ,
      "
      Neward
      "
      ,
      39
      ,
                
      new
       Person(
      "
      Michael
      "
      ,
      "
      Neward
      "
      ,
      16
      ),
                
      new
       Person(
      "
      Matthew
      "
      ,
      "
      Neward
      "
      ,
      10
      ));

             
      //
       Make a copy of the List
      

              List
      <
      Person
      >
       kids
      =
       
      new
       ArrayList
      <
      Person
      >
      (ted.getChildren());
             
      //
       Reverse it
      

              Collections.reverse(kids);
             
      //
       Display it
      

              System.out.println(kids);
         }
    }
      

    Collections类有一组这样的"算法",该类所实现的静态方法将Collections作为参数,并且提供了完全独立于任何实现的行为。
    另外,Collections类所示的算法在好的API设计中肯定不会是最终版本--例如,我不希望直接修改这些方法(由集合对象传入)的内容。你可以为自己编写定制的算法,这是一件很好的事情,如清单4所示:

    清单4. 简洁的反转迭代器
      
      
       
      class
       MyCollections
    {
         
      public
       
      static
       
      <
      T
      >
       List
      <
      T
      >
       reverse(List
      <
      T
      >
       src)
         {
             List
      <
      T
      >
       results
      =
       
      new
       ArrayList
      <
      T
      >
      (src);
             Collections.reverse(results);
             
      return
       results;
         }
    }
      

    5. 扩展的集合框架API
         上述定制的算法证明了Java集合API的最后一个问题:Java集合框架一直被设计为是可扩展的,可被改变以去适应开发者的特殊目的。
         例如,假设你需要Person中的children总是按年龄排序。虽然你可以一遍一遍地编写代码去对children进行排序(可能会使用 Collections.sort方法),要是有一个集合类能够帮你作这样的排序则会好得多。
         实际上,你可能并不关心添加到集合中的对象是以何种顺序存储的(这就是使用List的主要理由),你只是想让它们保持一定的顺序罢了。
         java.util包中没有哪一个集合类能满足这些需求,写一个却很容易。你所需要做的只是创建一个接口,该接口描述了该集合类需要提供的抽象行为。在 SortedCollection这个例子中,上述意图是完全可行的。

    清单5. SortedCollection
      
      
       
      public
       
      interface
       SortedCollection
      <
      E
      >
       
      extends
       Collection
      <
      E
      >
      
    {
         
      public
       Comparator
      <
      E
      >
       getComparator();
         
      public
       
      void
       setComparator(Comparator
      <
      E
      >
       comp);
    }
      

    基本上是虎头蛇尾般地写成了这个新接口的实现:

    清单6. ArraySortedCollection
      
      
       
      import
       java.util.
      *
      ;


      public
       
      class
       ArraySortedCollection
      <
      E
      >
      
         
      implements
       SortedCollection
      <
      E
      >
      , Iterable
      <
      E
      >
      
    {
         
      private
       Comparator
      <
      E
      >
       comparator;
         
      private
       ArrayList
      <
      E
      >
       list;
             
         
      public
       ArraySortedCollection(Comparator
      <
      E
      >
       c)
         {
             
      this
      .list
      =
       
      new
       ArrayList
      <
      E
      >
      ();
             
      this
      .comparator
      =
       c;
         }
         
      public
       ArraySortedCollection(Collection
      <?
       
      extends
       E
      >
       src, Comparator
      <
      E
      >
       c)
         {
             
      this
      .list
      =
       
      new
       ArrayList
      <
      E
      >
      (src);
             
      this
      .comparator
      =
       c;
             sortThis();
         }

         
      public
       Comparator
      <
      E
      >
       getComparator() {
      return
       comparator; }
         
      public
       
      void
       setComparator(Comparator
      <
      E
      >
       cmp) { comparator
      =
       cmp; sortThis(); }
         
         
      public
       
      boolean
       add(E e)
         {
      boolean
       r
      =
       list.add(e); sortThis();
      return
       r; }
         
      public
       
      boolean
       addAll(Collection
      <?
       
      extends
       E
      >
       ec)
         {
      boolean
       r
      =
       list.addAll(ec); sortThis();
      return
       r; }
         
      public
       
      boolean
       remove(Object o)
         {
      boolean
       r
      =
       list.remove(o); sortThis();
      return
       r; }
         
      public
       
      boolean
       removeAll(Collection
      <?>
       c)
         {
      boolean
       r
      =
       list.removeAll(c); sortThis();
      return
       r; }
         
      public
       
      boolean
       retainAll(Collection
      <?>
       ec)
         {
      boolean
       r
      =
       list.retainAll(ec); sortThis();
      return
       r; }
         
         
      public
       
      void
       clear() { list.clear(); }
         
      public
       
      boolean
       contains(Object o) {
      return
       list.contains(o); }
         
      public
       
      boolean
       containsAll(Collection
      <?>
       c) {
      return
       list.containsAll(c); }
         
      public
       
      boolean
       isEmpty() {
      return
       list.isEmpty(); }
         
      public
       Iterator
      <
      E
      >
       iterator() {
      return
       list.iterator(); }
         
      public
       
      int
       size() {
      return
       list.size(); }
         
      public
       Object[] toArray() {
      return
       list.toArray(); }
         
      public
       
      <
      T
      >
       T[] toArray(T[] a) {
      return
       list.toArray(a); }
         
         
      public
       
      boolean
       equals(Object o)
         {
             
      if
       (o
      ==
       
      this
      )
                
      return
       
      true
      ;
             
             
      if
       (o
      instanceof
       ArraySortedCollection)
             {
                 ArraySortedCollection
      <
      E
      >
       rhs
      =
       (ArraySortedCollection
      <
      E
      >
      )o;
                
      return
       
      this
      .list.equals(rhs.list);
             }
             
             
      return
       
      false
      ;
         }
         
      public
       
      int
       hashCode()
         {
             
      return
       list.hashCode();
         }
         
      public
       String toString()
         {
             
      return
       list.toString();
         }
         
         
      private
       
      void
       sortThis()
         {
             Collections.sort(list, comparator);
         }
    }
      

    这个应急式的实现,未经缜密的思索就写成了,毫无疑问它需要进行重构。但重点是,对于所有与集合相关的事情中,Java集合框架API原本就不是被设计成不需被修改的。它既需要也鼓励扩展。
         当然,有一些扩展会是有"重要职责"的变体,例如由java.util.concurrent包引用的扩展实现。但其它的一些则只是简单地编写一个定制算法,或是对已有集合类的一个简单扩展。
         扩展Java集合框架API看起来很具颠覆性,但一旦你开始做了,你就会发现并不如你所想像的那般困难。

    结论
         与Java序列化相同,Java集合框架API满是未被探究的细微之处--这也是为什么我们没有结束该主题的原因。5 things系列的下一篇文章将会向你展示使用Java集合框API做更多事情的另外5种方法。





      
      
       
       

         
       

         
       
      
    复制代码

    源码下载:http://file.javaxxz.com/2014/10/30/235548812.zip
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-25 22:06 , Processed in 0.555814 second(s), 46 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表