自定义泛型方法及其应用和类型参数的类型推断

自定义泛型方法用其应用

1. 定义泛型方法

a. java的泛型方法没有C++函数功能强大,java中的如下代码无法通过编译:

<T> T add(T x, T y) {

return (T) (x + y);

}

2. 交换数组中的两个元素的位置 //下面的方法很通用,这样做还是有意义的

private static <T> void swap(T[] a,int i, int j) {

T tmp = a[i];

a[i] = a[j];

a[j] = tmp;

}

3. 用于放置泛型的类型参数的尖括号应出现在方法的其它所有修饰符之后和在方法的返回类型之前,也就是紧邻返回之前。按照惯例,类型参数通常用单个大写字母表示。

例:private static <T> void swap(T[] a,int i, int j){};

4. 除了在应用泛型时可以使用extends 限定符,在定义泛型时也可以使用extends限定符,例如,Class.getAnnotation()方法的定义。并且可以用&来指定多个边界,
<V extends Serializable & cloneable> void method(){};

5. 普通方法、构造方法和静态方法中都可以泛型。

6 也可以用类型变量表示异常,称为参数化的异常,可以用于方法的throws列表中,但是不能用于catch子句中。 //貌似有点问题,报错

private static <T extends Exception> sayHello() throws T {

try {

 

}catch (Exception e) {

thorw (T)e;

}

}

7. 在泛型中可以同时有多个类型参数,在定义它们的类括号中用逗号分开,例如:

public static <K,V> V getValue(K key) {return map.get(key);}

编写一个泛型方法,自动将Object类型的对象转换成其它类型

private static <T> T autoConvert(Object obj) {

return (T) obj;

}

定义一个方法,可以将任意类型的数组中的所有元素填充为想方相应类型的某个对象

private static <T> void fillArray(T[] a, T obj) {

for (int i = 0; i < a.length; i++) {

a[i] = obj;

}

}

采用自定泛型方法的方式打印出任意参数化类型的集合中的所有内容。

在这种情况下,前面的通配符方案要比泛型方法更有效,当一个类型变量用来表达两个参数之间或者参数和值之间的关系时,即同一个类型变量在方法签名的两处被使用,或者类型变量在方法体中也被使用而不是仅在签名的时候使用,才需要使用泛型方法。

public static void printCollection(Collection<?> collection) {

System.out.println(collection.size());

for(Object obj: collection) {

System.out.println(obj);

}

}

 

public static <T> void printCollection2(Collection<T> collection, T obj2) {

System.out.println(collection.size());

for(Object obj: collection) {

System.out.println(obj);

}

collection.add(obj2);

}

定义一个方法,把任意参数类型的一个数组中的数据安全地复制到相应类型的集合中

定义一个方法,把任意参数类型的一个数组中的数据安全地复制到相应类型的别一个数组中

package cn.itcast.day2; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.Vector; public class GenericTest { public static void main(String[] args) { //Map接口并没有去实现Iterable接口,所以不能迭代,要交给Set集合完成 HashMap<String, Integer> maps = new HashMap<String, Integer>(); maps.put("张三", 29); maps.put("李四", 32); maps.put("王五", 33); Set<Map.Entry<String, Integer>> entrySet = maps.entrySet(); for (Map.Entry<String, Integer> entry: entrySet) { System.out.println(entry.getKey() + ":" + entry.getValue()); } add(3, 5); //->Integer add(3.5, 3); //->Number add(3, "abc"); //->Object String[] s = new String[]{"abc","xyz","itcast"}; swap(s,1,2); System.out.println(Arrays.asList(s)); // swap(new int[]{1,3,5,4,5},3,4); 这样做不行,泛型接受的必须是引用类型,下面的可行 Integer[] integer = new Integer[]{1,2,3}; swap(integer, 1, 2); System.out.println(Arrays.asList(integer)); Object obj = "abc"; String x3 = autoConvert(obj); // copyArrayToArray(new Date[10], s); 会报错? // copyArrayToArray(new Vector<Date>(), new String[10]); 限定了只能传Date Vector<String> vs = new Vector<String>(); copyCollectionToArray(vs, s); //将S数组中的数据复制到了可变数组中 /* for (int i = 0; i < vs.size(); i++) { System.out.println(vs.get(i)); } */ Iterator<String> it = vs.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } private static <T> T add(T x, T y) { return x; } private static <T> void swap(T[] a,int i, int j) { T tmp = a[i]; a[i] = a[j]; a[j] = tmp; } /* private static <T extends Exception> sayHello() throws T { try { }catch (Exception e) { thorw (T)e; } }*/ /** * 编写一个泛型方法,自动将Object类型的对象转换成其它类型 */ private static <T> T autoConvert(Object obj) { return (T) obj; } /** * 定义一个方法,可以将任意类型的数组中的所有元素填充为想方相应类型的某个对象 */ private static <T> void fillArray(T[] a, T obj) { for (int i = 0; i < a.length; i++) { a[i] = obj; } } public static void printCollection(Collection<?> collection) { System.out.println(collection.size()); for(Object obj: collection) { System.out.println(obj); } } public static <T> void printCollection2(Collection<T> collection, T obj2) { System.out.println(collection.size()); for(Object obj: collection) { System.out.println(obj); } collection.add(obj2); } /** * 把任意参数类型的一个数组中的数据安全地复制到相应类型的别一个数组中 * @param <T> * @param desc * @param src */ public static <T> void copyArrayToArray(T[] desc, T[] src) { for (int i = 0; i < src.length; i++) { desc[i] = src[i]; } } /** * 把任意参数类型的一个数组中的数据安全地复制到相应类型的集合中 * @param <T> * @param desc * @param src */ public static <T> void copyCollectionToArray(Collection<T> desc, T[] src) { for(int i = 0; i < src.length; i++) { desc.add(src[i]); } } }

类型参数的类型推断

1. 编译器判断泛型的实际类型参数的过程称为类型推断,类型推断是相对于知觉推断的,其实现方法是一种子选手非常复杂的过程。

2. 根据调用泛型方法时实际传递的参数类型或值的类型来推断,具体规则如下:
a.
当草棚个类变量只在整个参数列表中的所有和返回值中的一处被应用了,那么根据调用 方法时该处的实际应用类型来确定,这很容易凭着感觉推断来来,即直接根据调用方法时传递的参数类型或返回值来决定泛型参数的类型。例如:

swap(new String[3],3,4)->static <E> void Swap(E[] a, int i, int j);

b. 当某个类型变更在整个参数列表中所胡参数和返回值的多处被应用了,如果调用方法时这多处的实际应用类型都对就同各种类型来确定,这很容易凭感觉推断出来,例如:
add(3,5)->static <T> add(T a, T b);

c. 当某个类型变量在整个参数列表中的所有值和返回值中的多处被应用了,如果说调用方法时这多处的实际应用类型对应到了不同的类型,且没有使用返回值,这时候取多个参数的最大交集类型,例如,下面语句实际对应的类型就是Number了,编译没问题,只是运行时出问题:
fill(new Integer[3], 3,5f) -> static <T> void fill(T[] a, T v);

d. 当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型对应到了不同的类型,并且使用返回值,这时候优先考虑返回值的类型,例如,下面的语句实际对应的类型就是Integer了,编译器将报告错误,将变量X的类型改为float,对比Eclipse报告错误提示,接着再将变量X类型改为Number,则没有了错误:

int x = (3.35f) -> sttic <T> add(T a, T b);

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值