zoukankan      html  css  js  c++  java
  • 8.4 泛型方法

    一、定义泛型方法

    所谓泛型方法,就是在声明方法时定义一个多个泛型形参。泛型方法的语法格式:

    修饰符 <T,S> 返回值类型 方法名(形参列表)
    {
        ///    方法体
    }
    

    泛型形参声明以尖括号括起来,多个泛型形参之间以逗号(,)隔开,所有泛型形参声明方法在修饰符和方法返回值类型之间
    问题:将一个Object数组的所有元素添加到一个Collection集合中。

    import java.util.*;
    public class GenericMethodTest 
    {
    	//声明一个泛型方法,该泛型方法中带有一个T泛型形参
    	static <T> void fromArrayToCollection(T[] a,Collection<T> c)
    	{
    		for(T o:a)
    		{
    			c.add(o);
    		}
    	}
    	public static void main(String[] args) 
    	{
    		var oa=new Object[100];
    		Collection<Object> co=new ArrayList<>();
    		//下面代码的T代表Object类型
    		fromArrayToCollection(oa,co);
    
    
    		//下面代码的T代表String类型
    		var sa=new String[100];
    		Collection<String> cs=new ArrayList<>();
    		fromArrayToCollection(sa,cs);
    		
    		//下面代码的T代表Object类型
    		fromArrayToCollection(sa,co);
    
    		var ia=new Integer[100];
    		var fa=new Float[100];
    		var na=new Number[100];
    		Collection<Number> cn=new ArrayList<>();
    		//下面代码T代表Number类型
    		fromArrayToCollection(ia,cn);
    		//下面代码T代表Number类型
    		fromArrayToCollection(fa,cn);
    		//下面代码T代表Number类型
    		fromArrayToCollection(na,cn);
    
    		//下面代码T代表Object类型
    		fromArrayToCollection(na,co);
    
    		//下面代码T代表String类型,但na是一个Number数组
    		//因为Number既不是String类型,也不是它的子类,所以出现编译错误
    		fromArrayToCollection(na,cs);
    	}
    }
    ---------- 编译Java ----------
    GenericMethodTest.java:44: 错误: 无法将类 GenericMethodTest中的方法 fromArrayToCollection应用到给定类型;
    		fromArrayToCollection(na,cs);
    		^
      需要: T[],Collection<T>
      找到: Number[],Collection<String>
      原因: 推论变量 T 具有不兼容的上限
        等式约束条件:String
        下限:Number
      其中, T是类型变量:
        T扩展已在方法 <T>fromArrayToCollection(T[],Collection<T>)中声明的Object
    1 个错误
    
    输出完成 (耗时 4 秒) - 正常终止
    

    与类、接口中使用的泛型参数不同的是,方法中的泛型参数无需显式地传入实际类型参数,如上面程序所示,当程序中调用fromArrayToCollection()方法时,无需传入在调用该方法前传入String、Object等类型,但系统依然可以知道为泛型实际的类型,因为编译器根据实参推断出泛型所代表的类型,它通常推断出最直接的类型。例如,下面调用代码:

    fromArrayToCollection(sa,cs);
    

    cs是一个Collection类型,与方法定义时的fromArrayToCollection(T[] a,Collection c)进行比较——只比较泛型参数,不难发现T类型代表的实际类型是String类型。
    对于如下调用代码

    fromArrayToCollection(ai,cn);
    

    cn是一个Collection类型,与方法定义时的fromArrayToCollection(T[] a,Collection c)进行比较——只比较泛型参数,不难发现T类型代表的实际类型是Number类型,Integer是Number的子类,子类类型变量可以自动转化为父类类型变量。

    为了编译器能够正确推断出泛型方法中泛型的类型,不要制造迷惑!一旦系统迷惑,将出现编译错误:

    import java.util.*;
    public class ErrorTest 
    {
    	//声明一个泛型方法,该泛型中带有一个T泛型形参
    	static <T> void test(Collection<T> from,Collection<T> to)
    		//将集合from的元素添加到集合to中
    	{
    		for(var ele:from)
    		{
    			to.add(ele);
    		}
    	}
    	public static void main(String[] args) 
    	{
    		//当两个集合元素都相同时,系统可以推断出正确泛型类型
    		List<Integer> ic1=new ArrayList<>();
    		ic1.add(1);
    		ic1.add(2);
    		ic1.add(3);
    		List<Integer> ic2=new ArrayList<>();
    		test(ic1,ic2);//此时test()方法的泛型类型为Integer
    		System.out.println(ic2);//[1,2,3]
    
    		//当两个集合元素不同时,系统将迷惑
    		List<Object> as=new ArrayList<>();
    		ic1.add(1);
    		ic1.add(2);
    		ic1.add(3);
    		List<String> ao=new ArrayList<>();
    		test(as,ao);//此时无法判断test()方法的泛型类型
    		System.out.println(ao);
    	}
    }
    ---------- 编译Java ----------
    ErrorTest.java:21: 错误: 无法将类 ErrorTest中的方法 test应用到给定类型;
    		test(ic1,ic2);//此时test()方法的泛型类型为Integer
    		^
      需要: Collection<T>,Collection<T>
      找到: List<Integer>,List<Number>
      原因: 推论变量T具有不兼容的等式约束条件Number,Integer
      其中, T是类型变量:
        T扩展已在方法 <T>test(Collection<T>,Collection<T>)中声明的Object
    ErrorTest.java:30: 错误: 无法将类 ErrorTest中的方法 test应用到给定类型;
    		test(as,ao);//此时test()方法的泛型类型为Integer
    		^
      需要: Collection<T>,Collection<T>
      找到: List<Object>,List<String>
      原因: 推论变量T具有不兼容的等式约束条件String,Object
      其中, T是类型变量:
        T扩展已在方法 <T>test(Collection<T>,Collection<T>)中声明的Object
    2 个错误
    
    输出完成 (耗时 1 秒) - 正常终止
    

    上面程序传入test()方法的两个实际参数,其中as的数据类型是List

  • 相关阅读:
    Java多线程系列--“基础篇”11之 生产消费者问题
    Java多线程系列--“基础篇”10之 线程优先级和守护线程
    Java多线程系列--“基础篇”09之 interrupt()和线程终止方式
    Java多线程系列--“基础篇”08之 join()
    Java四种线程池的使用
    数据库索引的实现原理
    Java多线程系列--“基础篇”07之 线程休眠
    Java多线程系列--“基础篇”06之 线程让步
    Java多线程系列--“基础篇”05之 线程等待与唤醒
    Java多线程系列--“基础篇”04之 synchronized关键字
  • 原文地址:https://www.cnblogs.com/weststar/p/12601591.html
Copyright © 2011-2022 走看看