泛型方法
来源:互联网 发布:电影人工智能结局 编辑:程序博客网 时间:2024/05/16 02:02
@author LeslieTong
@data 2017-11-20
Stay hungry, stay foolish. ——Steve·Jobs
定义泛型方法
假设需要实现一个方法——该方法负责将一个Object数组的所有元素添加到一个Collection集合中。
考虑采用如下代码来实现该方法。
static void fromArrayToCollection(Object[] a, Collection<Object> c) { for (Object o: a) { c.add(o); }}
上面定义的方法没有任何问题,关键在于方法中的c形参,它的数据类型是Collection。
正如前面所介绍的,Collection< String >不是Collection< Object >的子类型——所以这个方法的功能非常有限,它只能将Object数组的元素复制到Object(Object的子类不行)Collection集合中,
即下面代码将引起编译错误。
String[] strArr = {"a", "b"};List<String> strList = new ArrayList<>();// Collection<String>对象不能当成Collection<Object>使用,下面代码出现编译错误fromArrayToCollection(strArr, strList);
可见上面方法的参数类型不可以使用Collection< String >,那使用通配符Collection
修饰符 <T, S> 返回值类型 方法名(形参列表) { // 方法体}
于是可以把上面的fromArrayToCollection方法改为如下格式:
static <T> void fromArrayToCollection(T[] a, Collection<T> c) { for (T o : a) { c.add(o); }}
下面程序示范了完整的用法。
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) { Object[] oa = new Object[100]; Collection<Object> co = new ArrayList<>(); // 下面代码T代表Object类型 fromArrayToCollection(oa, co); String[] sa = new String[100]; Collection<String> cs = new ArrayList<>(); // 下面代码T代表String类型 fromArrayToCollection(sa, cs); // 下面代码中T代表Object类型 fromArrayToCollection(sa, co); Integer[] ia = new Integer[100]; Float[] fa = new Float[100]; Number[] 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); }}
为了让编译器能准确推断出泛型方法中类型形参的类型 ,不要制造迷惑。
一旦系统迷惑了,就是你错了! ——李刚
看如下程序
public class ErrorTest { // 声明一个泛型方法,该泛型方法中带一个T类型参数 static <T> void test(Collection<T> from, Collection<T> to) { for (T ele : from) { to.add(ele); } } public static void main(String[] args) { List<Object> as = new ArrayList<>(); List<String> ao = new ArrayList<>(); // 下面代码将产生编译错误 //test(as, ao); }}
上面程序定义了test方法,该方法用于将前一个集合里的元素复制到下一个集合中,该方法中的两个形参from、to的类型都是Collection,这要求调用该方法时的两个集合实参中的泛型类型相同,否则编译器无法准确推断出泛型方法中类型形参的类型。
上面程序中调用test方法传入了两个实际参数,其中as的数据类型是List,而ao的数据类型是List,与泛型方法签名进行对比:test(Collection< T > a, Collection< T> c),编译器无法正确识别T所代表的实际类型。为了避免这种错误,可以将该方法改为如下形式 :
public class RightTest { // 声明一个泛型方法,该泛型方法中带一个T类型参数 static <T> void test(Collection<? extends T> from, Collection<T> to) { for (T ele : from) { to.add(ele); } } public static void main(String[] args) { List<Object> ao = new ArrayList<>(); List<String> as = new ArrayList<>(); // 下面代码正常 test(as, ao); }}
上面代码改变了test方法签名,将该方法的前一个形参类型改为Collection< ? extends T>,这种采用类型通配符的表示方式,只要test方法的前一个Collection集合里的元素类型是后一个Collection集合里元素类型的子类即可。
泛型方法和类型通配符的区别
大多数时候都可以用泛型方法代替类型通配符。例如,对于Collection接口中两个方法定义:
public interface Collection<E> { boolean containsAll(Collection<?> c); boolean addAll(Collection<? extends E> c); ...}
我们看到上面两个方法都使用了类型通配符的形式,下面我们用泛型方法的形式:
public interface Collection<E> { boolean <T> containAll(Collection<T> c); boolean <T> allAll(Collection<T> c); ...}
上面方法使用了< T extends E >泛型形式,这时定义类型形参时设定上限。其中E是Collection接口里定义的类型形参,在该接口里E可当成普通类型使用。
设定通配符下限
Java允许设定通配符的下限:\< ? super Type>,这个通配符表示它必须是Type本身或者Type的父类。代码如下:
public class MyUtils { // 下面des集合元素的类型必须与src集合元素的类型相同或者是其父类 public static <T> T copy (Collection<? super T> des, Collection<T> src) { T last = null; for (T ele : src) { last = ele; des.add(ele); } return last; } public static void main(String[] args) { List<Number> ln = new ArrayList<>(); List<Integer> li = new ArrayList<>(); li.add(5); // 此处可准确知道最后一个被复制的元素是Integer类型 // 与src集合元素类型相同 Integer last = copy(ln, li); System.out.println(ln); }}
- 泛型方法和可变参数方法
- 泛型方法与普通方法
- 自定义泛型方法
- 泛型方法
- c# 泛型方法
- 泛型方法
- 泛型方法2
- 泛型方法
- 泛型方法
- 泛型类 泛型方法
- 扩展泛型方法
- 泛型方法
- Java泛型方法
- 泛型类 泛型方法
- 泛型方法
- 泛型方法
- 泛型方法
- 泛型方法
- 输入两个整数,排序,使用变量的引用
- Continuous Subarray Sum
- Android应用层View绘制流程与源码分析
- 0002
- 购物车二级列表的实现,在一级列表基础上,bean类里再添加两个字段(请求本地json数据)
- 泛型方法
- eclipse转AS方法2——新目录结构
- 操作符简单剖析
- (十)、Java复习笔记之多线程(1)
- android AES对称加密算法使用实例
- HDU
- SpringBoot--Profile
- spring boot 项目三种启动方式
- 电路实验