Java 泛型方法/接口、泛型限定

Java 泛型方法/接口、泛型限定文章目录

 文章目录 一、为什么要定义泛型方法 1、从泛型类到泛型方法的演变过程 2、定义泛型方法的好处 二、创建一个泛型方法格式 常用的形式 三、泛型接口 1、格式 2、例子 四、类型通配符(泛型的高级应用) 1、什么是通配符 (?) 2、类型通配符上限定(? extends T =>可以接收T类型或者T的子类型) 3、类型通配符下限定 (? super T => 可以接收T类型或者T父类型) 

一、为什么要定义泛型方法

1、从泛型类到泛型方法的演变过程
我们先来看个例子

//定义一个泛型类,并定义如下两个方法 class Test 
  
    { public void show(T t){ System.out.println(t); } public void print(T t){ System.out.println(t); } /* 以前是这样定义,现在一个方法搞定 public void show(String t){ } public void show(Integer t){ } 或者 public void show(Object obj){ } */ } //在manin方法代码如下 public static void main(String[] args) { Test 
   
     d = new Test 
    
      (); d.show("java"); d.print("Object-C"); Test 
     
       e = new Test 
      
        (); e.show(2); e.print(new Integer(5)); } 
       
      
     
    
  

上面是一个简单的代码demo,运行没问题,正常输出。但是你会发现,其实代码有点冗余。我们定义了一个泛型类,并定义了 show(T t)print(T t)方法。发现: 泛型类定义的泛型,在整个类中有效如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所要操作的类型已经固定了。就像上面main方法中。对象d,只能操作String类型,如果你要操作其他类型,只能额外去创建其他泛型对象e

设想下,如果我能把泛型定义在方法上,这样不就可以优雅解决问题。于是变化代码如下

//定义一个类,并定义如下两个泛型方法 class Test { public 
  
    void show(T t){ System.out.println(t); } public 
   
     void print(T t){ System.out.println(t); } public 
    
      void sum(U u,T t){ System.out.println(u+" version is "+t); } } // main方法如下 public static void main(String[] args) { Test d = new Test(); d.show("java"); d.print(5); d.sum("java", new Double(8)); } 
     
    
  

Test不再是泛型类,泛型方法show(T t)print(T t)sum(U u,T t) 更具有扩展性。

2、定义泛型方法的好处

泛型方法可以让不同方法操作不同类型,且类型还不确定。 与泛型类不同,泛型方法的类型参数只能在它锁修饰的泛型方法中使用。 

二、创建一个泛型方法格式

1、常用的形式

访问修饰符 [static][final] 
  <类型参数列表>
    返回值类型 方法名([形式参数列表]) 
  

备注:[] 代可有可无的意思,泛型方法可以是实例方法或静态方法,类型参数可以在静态方法中,这是与泛型类最大的区别

三、泛型接口

1、格式

interface 接口名 
  <类型参数表> 
  

2、例子

定义一个泛型接口

interface showInterface 
  
    { public void show(T t); } 
  

(1) 实现类确定了类型

class ShowClass implements showInterface 
  
    { public void show(String t){ System.out.println("show:"+t); } } 
  

(2) 实现类类型不确定

class ShowClass 
  
    implements showInterface 
   
     { public void show(T t){ System.out.println("show:"+t); } } 
    
  

main方法

 public static void main(String[] args) { ShowClass 
  
    obj = new ShowClass 
   
     (); obj.show(6); /* ShowClass obj = new ShowClass(); obj.show("java"); */ } 
    
  

四、类型通配符(泛型的高级应用)

1、什么是通配符 (?)
看个例子就明白了。定义两个集合,分别输出两个集合的元素。

 public static void main(String[] args) { ArrayList 
  
    a1 = new ArrayList 
   
     (); a1.add("a"); a1.add("b"); a1.add("c"); ArrayList 
    
      a2 = new ArrayList 
     
       (); a2.add(1); a2.add(2); a2.add(3); } 
      
     
    
  

在我们没学习泛型之前,我们会封装静态方法如下:

 public static void printList(ArrayList list){ for (Iterator iterator = list.iterator(); iterator.hasNext();) { Object object = (Object) iterator.next(); System.out.println(object); } } 

代码买啥毛病,运行也正确。会有一个疑问。为什么参数没定义泛型,但是却可以接受泛型呢?泛型是jdk1.5出来的,老版本肯定要兼容新版本。

在我们学习泛型方法后,我们进一步将代码修改如下:

 public static 
  
    void vistor(ArrayList 
   
     a){ Iterator 
    
      iterator = a.iterator(); while(iterator.hasNext()){ T t = iterator.next(); System.out.println(t); } } 
     
    
  

定义一个泛型方法。如果是泛型类,是不允许泛型定义在static上面的

如果不想定义泛型方法,又能够解决问题呢?这就要用到一个通配符的玩意

 //占位符,也称为通配符。表示元素类型可以匹配任意类型 public static void sop(ArrayList 
   a){ for(Iterator 
   it = a.iterator();it.hasNext();){ System.out.println(it.next()); } } 

泛型方法T如果是具体类型的话,可以接收T t = iterator.next();。?是占位符,不明确具体类型,无法接收。

这种带通配符ArrayList
a
List 仅仅表示他是各种泛型的父类,并不能把元素添加到其中。

我做了奇怪的例子

 ArrayList 
   list = new ArrayList 
  
    (); list.add(null); 
  

上面说,带通配符ArrayList
a
List 仅仅表示他是各种泛型的父类,并不能把元素添加到其中。是不是想违背了?仔细想想,null是任意引用类型的实例。这比较特殊。

2、类型通配符上限定(? extends T)

同样看一个例子. 定义一个集合,遍历元素的方法并输出。

//定义一个Person类 class Person { private String name; public Person(String name){ this.name = name; } public String getNmae(){ return this.name; } } // 定义一个Student 并继承 Person class Student extends Person { Student(String name){ super(name); } } main方法如下 public static void main(String[] args) { ArrayList 
  
    a1 = new ArrayList 
   
     (); a1.add(new Person("abc1")); a1.add(new Person("abc2")); a1.add(new Person("abc3")); printMethod(a1); // 下面是错误的。a2存的是Person,存在继承的话,也能放worker。但是等号右边只能存Student,存不进worker.类型安全问题。左右两边要一致 ArrayList 
    
      a2 = new ArrayList 
     
       (); a2.add(new Student("abc--1")); a2.add(new Student("abc--2")); a2.add(new Student("abc--3")); printMethod(a2); // ArrayList 
      
        a2 = new ArrayList 
       
         (); //如果我想调用也printMethod(a2);没毛病。怎么做?。 第一想法直接给占位符。但是带来一问题,不能调用具体方法。 } // 与main方法同级的静态工具类方法 public static void printMethod(ArrayList< Person> a1){ Iterator 
        
          it = a1.iterator(); while(it.hasNext()){ System.out.println(it.next().getNmae()); } } 
         
        
       
      
     
    
  

如果我想调用也printMethod(a2);没毛病。怎么做?。 第一想法直接给占位符。但是带来一问题,不能调用具体方法。泛型也是一样的。如果我们想两者兼得,既能打印Stuednt,也能打印 Person,我们将printMethod修改如下

 public static void printMethod(ArrayList 
   a1){ Iterator 
   it = a1.iterator(); while(it.hasNext()){ System.out.println(it.next().getNmae()); } } 

我们称? extends T 为 泛型上限定: 可以接收T和T的子类

3、类型通配符下限定

TreeSet 
  
    ts = new TreeSet 
   
     (); //Comparator 
     comparator ts.add(new Person("d")); ts.add(new Person("f")); ts.add(new Person("g")); 
    
  

比较器如下

// 这边的T写Student和Person都是可以的 class comp implements Comparator 
  
    { public int compare(Person s1,Person s2){ return s1.getNmae().compareTo(s2.getNmae()); } } 
  

其实限定的目的是为了扩展指定类型。

通过上面比较器参数和我们实现的比较器。如果我们比较器的泛型为 Student,那么只能比较Student。当未来某一天,Person有新子类出现的话,那么该比较器就不适用了。所以Java 的API 的考虑扩展性的同时,已经设置了泛型下限定,你可以传T类型或者T的父类型。

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/205665.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午5:29
下一篇 2026年3月19日 下午5:29


相关推荐

  • arcgis附图制作_怎么制作图片的浮雕效果

    arcgis附图制作_怎么制作图片的浮雕效果ArcGIS制作地图时可以制作出很多很炫的效果,比如地图阴影、地图晕渲效果、浮雕效果、三维效果等等。本实验讲解在ArcGIS中制作浮雕效果地图,效果如下所示:1.加载矢量数据加载实验数据包data44.rar中的秦安县乡镇矢量数据:2.缓冲区分析点击【地理处理】下拉菜单,点击【缓冲区】。输入要素选择秦安县乡镇数据,选择输出要素路径,线性单位输入-0.4,单位为千米,侧类型选择两侧,融合类型选择ALL,点击确定。缓冲区效果:3.欧氏距离分析欧氏距离工具用于计算每个像元到最近.

    2025年9月15日
    7
  • 清除SVN未版控文件

    清除SVN未版控文件

    2021年10月20日
    46
  • java二维数组初始化导入案例_Java二维数组初始化的方法详解

    java二维数组初始化导入案例_Java二维数组初始化的方法详解对于一个新使用的工具,我们会进行初步的初始化工具,目的是为了加上一些使用的配置。在学过了一维数组后,那么二维数组是加了一层维度的一维数组。在初始化方面,二维数组有三种方法,相信很多人只是掌握了其中的一种。下面本篇就Java二维数组简单介绍,然后就三种初始化方法带来详解。1.二维数组说明数组是一个容器,用来存储数据的。现在数组中存储的不再是int,double..的类型了,而是存储的数组。数组中的元…

    2022年5月25日
    51
  • EEMD算法原理及应用

    EEMD算法原理及应用本博客主要概括 EEMD 算法的背景 原理以及应用 利用 EEEMD 对信号进行分解 然后选择有用的 IMF 分量进行叠加以完成信号的重构 从而实现对信号降噪 本文配套的源代码见文中链接 可供大家免费下载

    2026年3月19日
    2
  • varchar2和varchar2(char)_datetime数据类型

    varchar2和varchar2(char)_datetime数据类型charvarcharvarchar2的区别 区别:1.CHAR的长度是固定的,而VARCHAR2的长度是可以变化的,比如,存储字符串“abc”,对于CHAR(20),表示你存储的字符将占20个字节(包括17个空字符),而同样的VARCHAR2(20)则只占用3个字节的长度,20只是最大值,当你存储的字符小于20时,按实际长度存储。 2.CHAR的效率比VARCHAR2的效

    2022年4月20日
    51
  • c# WinForm开发 DataGridView控件的各种操作总结(单元格操作,属性设置)

    c# WinForm开发 DataGridView控件的各种操作总结(单元格操作,属性设置)

    2021年12月10日
    51

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号