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入门到精通教程
查看: 428|回复: 0

[泛型学习]在泛型中使用通配符和继承

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

    [LV.1]初来乍到

    发表于 2014-10-29 23:56:32 | 显示全部楼层 |阅读模式
    本文是Sun官方以Blog形式发布的java核心技术窍门(JavaCoreTechTip)中的一篇,它以非常简洁的示例展示了泛型通配符的使用,初学Java泛型的朋友可以看看。(2009.12.30最后更新)

         Java2平台,标准版5.0(J2SE 5.0)为Java程序设计语言及其平台引入了泛型。在最简单的案例和典型的应用中,泛型能够识别集合容器中所存储的是否是你所期望的对象。

        所以,你可以特别说你有一个String或其它类型对象的List,而不是声称你的程序有一个Object的List。所以,如果你不小心向该List中加入了错误类型的对象,编译器会告之你这个错误。该错误将在编译时进行修复,而不用等到你运行该程序,且在程序运行到该处代码时,在获取对象的操作中产生一个运行时的强制类型转换异常。

    这就提出了泛型的第二个好处。迭代器将变得类型安全了。Iterator接口中的next()方法将会返回集合中下一个元素的类型安全版本。  
      
       
       
         
       

         
       
      


       

         但这并不是本文要介绍的泛型应用的窍门,那些窍门已由
    2005 Core Java Technologies Tip描述过了。在使用泛型时,大多数人都不能很好地理解对extends关键字的使用。一个典型的描述如何使用
    extends关键字的示例与绘制图形有关。与其不同的是,此处窍门所用的示例将使用Swing组件,以便你不必创建额外的新类。在一个非常有限的例子中,Swing按钮组件的类层次结构如下所示,当然,Object是实际上的根。


      
       
      Component

      |-
       Container
       
      |-
       JComponent
          
      |-
       AbstractButton
             
      |-
       JButton
             
      |-
       JMenuItem
                
      |-
       JCheckBoxMenuItem
                
      |-
       JMenu
                
      |-
       JRadioButtonMenuItem
             
      |-
       JToggleButton
                
      |-
       JCheckBox
                
      |-
       JRadioButton
      

         所有AbstractButton的子类都共同享有的一个东西就是方法getText。这就是泛型的精髓,你能定义一个方法去处理以AbstractButton为元素的List,并返回这些按钮的String类型的标签的List。下面是该方法的第一个版本:
      
      
       
      public
       
      static
       List
      <
      String
      >
       getLabels(List
      <
      AbstractButton
      >
       list) {
         List
      <
      String
      >
       labelList
      =
       
      new
       ArrayList
      <
      String
      >
      (list.size());
         
      for
       (AbstractButton button: list) {
             labelList.add(button.getText());
         }
         
      return
       labelList;
    }
      

         下面就是如何使用该方法。首先,定义一个AbstractButton类型的List,然后向其中填充值,并调用该方法:
      
      
       
      List
      <
      AbstractButton
      >
       buttonList
      =
       
      new
       ArrayList
      <
      AbstractButton
      >
      ();
    buttonList.add(
      new
       JButton(
      "
      Hello
      "
      ));
    buttonList.add(
      new
       JCheckBox(
      "
      World
      "
      ));
    buttonList.add(
      new
       JRadioButton(
      "
      Hola
      "
      ));
    buttonList.add(
      new
       JMenuItem(
      "
      Mundo
      "
      ));

    List labels
      =
       getLabels(buttonList);
    System.out.println(labels);
      

         根据Google,"Hola, Mundo"是"Hello, World"的西班牙译文。调用println()方法的结果如下所示:

    [Hello, World, Hola, Mundo]



         对于
    AbstractButton的
    List对象,一切都能正常运行,但当是其它类型,特别是AbstractButton子类型的List时,就不能正常工作了。从逻辑上,有人可能认为对于以JButton为元素的List,一切仍能正常工作。因为JButton是AbstractButton的子类。难道不能对AbstractButton子类型的List调用方法
    getLabels(List<AbstractButton>)?

    然而,事实并非如此。因为这是一个编译时检查,同时也因为getLabels方法被定义为只接受AbstractButton的List,你不能向该方法中传入任何其它类型的List。

      
      
       
      GetList.java:
      13
      : getLabels(java.util.List
      <
      javax.swing.AbstractButton
      >
      )
       in GetList cannot be applied to (java.util.List
      <
      javax.swing.JButton
      >
      )

         List
      <
      String
      >
       labels
      =
       getLabels(buttonList);
                               
      ^
      

      1
       error
      

    这也就是extends关键字发挥作用的地方了。不将getLabes方法定义为仅仅接受AbstractButton List,而是将它定义为接受AbstractButton子类的List:
      
      
       
      public
       
      static
       List
      <
      String
      >
       getLabels(
             List
      <?
       
      extends
       AbstractButton
      >
       list)
      

    此处的通配符?表明该方法并不关心确切的类型是什么,只要它是AbstractButton的子类型即可。下面是综合了前述所有代码片断的完整示例程序:
      
      
       
      import
       java.util.
      *
      ;

      import
       javax.swing.
      *
      ;


      public
       
      class
       GetList {
         
      public
       
      static
       
      void
       main(String args[]) {
             List
      <
      JButton
      >
       buttonList
      =
      
                     
      new
       ArrayList
      <
      JButton
      >
      ();
             buttonList.add(
      new
       JButton(
      "
      Hello
      "
      ));
             buttonList.add(
      new
       JButton(
      "
      World
      "
      ));
             buttonList.add(
      new
       JButton(
      "
      Hola
      "
      ));
             buttonList.add(
      new
       JButton(
      "
      Mundo
      "
      ));

             List labels
      =
       getLabels(buttonList);
             System.out.println(labels);
         }

         
      public
       
      static
       List
      <
      String
      >
       getLabels(
                 List
      <?
       
      extends
       AbstractButton
      >
       list) {
             List
      <
      String
      >
       labelList
      =
       
      new
       ArrayList
      <
      String
      >
      (list.size());
             
      for
       (AbstractButton button: list) {
                 labelList.add(button.getText());
             }
             
      return
       labelList;
         }
    }
      

    现在,当你要用泛型来定义你自己的类和方法时,就要考虑接受作为泛型参数的抽象类,或它的任一超类,记得使用通配符以便相同的方法对于子类也能很好地工作。

    更多关于泛型的信息,请见两篇较早前由Gilad Bracha撰写的教程:一篇是
    2004年的教程(PDF),另一篇是在线的
    Java Tutorial中的泛型章节。




      
      
       
       

         
       

         
       
      
    复制代码
    回复

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2025-2-26 01:18 , Processed in 0.428633 second(s), 36 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

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