泛型方法重载
泛型既允许设定通配符的上限,也允许设定通配符的下限,从而允许在一个类里包含如下两个方法定义:
public class MyUtils
{
public static <T> void copy(Collection<T> dest, Collection<? extends T> src)
{
...
}
public static <T> T copy(Collection<? super T> dest, Collection<T> src)
{
...
}
}
该类中包含两个copy()方法,这两个方法的参数列表存在一定的区别,但这种区别不是很明确:这两个方法的两个参数都是Collection对象,前一个集合里的集合元素类型是后一个集合里集合元素类型的父类。如果只是在该类中定义这两个方法不会有任何错误,但只要调用这个方法就会引起编译错误
List<Number> ln = new ArrayList<>();
List<Integer> li = new ArrayList<>();
copy(ln, li);
代码调用copy()方法,但这个copy()方法可以匹配类中的两个方法中任何一个,匹配第一个方法泛型T表示的类型就是Number,匹配第二个方法,泛型T就表示类型Integer,编译器是无法确定这行代码想调用哪个copy()方法的,必然引起编译错误
Java8改进类型推断
Java8改进了泛型方法的类型推断能力“
- 可通过调用方法的上下文来推断泛型的目标类型
- 可在方法调用链中,将推断得到的泛型传递到最后一个方法
class MyUtil<E>
{
public static <Z> MyUtil<Z> nil()
{
return null;
}
public static <Z> MyUtil<Z> cons(Z head, MyUtil<Z> tail)
{
return null;
}
E head()
{
return null;
}
}
public class InferenceTest
{
public static void main(String[] args)
{
// 可以通过方法赋值的目标参数来推断类型参数为String
MyUtil<String> ls = MyUtil.nil();
// 无需使用下面语句在调用nil()方法时指定类型参数的类型
MyUtil<String> mu = MyUtil.<String>nil();
// 可调用cons方法所需的参数类型来推断类型参数为Integer
MyUtil.cons(42, MyUtil.nil());
// 无需使用下面语句在调用nil()方法时指定类型参数的类型
MyUtil.cons(42, MyUtil.<Integer>nil());
// 希望系统能推断出调用nil()方法类型参数为String类型,
// 但实际上Java 8依然推断不出来,所以下面代码报错
// String s = MyUtil.nil().head();
// 将代码做如下修改
String s = MyUtil.<String>nil().head();
}
}
MyUtil<String> ls = MyUtil.nil();
无须在调用nil()方法时显式的指定泛型参数为String,因为程序需要将该方法的返回值赋值给MyUtil<String>类型,因此系统可以自动推断出此处的泛型参数为String类型
MyUtil.cons(42, MyUtil.nil());
也无须在盗用nil()方法时显式指定泛型参数为Integer,因为程序将nil()方法的返回值作为MyUtil类的cons()方法的第二个参数,而程序可以根据cons()方法的第一个参数42推断出此处的泛型参数为Integer类型
但是泛型推断不是万能的
// 希望系统能推断出调用nil()方法类型参数为String类型,
// 但实际上Java 8依然推断不出来,所以下面代码报错
// String s = MyUtil.nil().head();
// 将代码做如下修改
String s = MyUtil.<String>nil().head();