之前翻看java源码时,发现过<T extends Comparable<? super T>>这样的泛型声明,当时看到这种声明实在是不太能理解,只知道泛型中extends表明可以接收子类,List<? extends Fruit> a;Fruit b = a.get();
super会限定下界用于保证能操作(如add,remove)子类集合。List<? super Apple> a1; List<Apple> a2; a1.addAll(a2);
但当它们合起来用的时候,就让我觉得很懵。偶然又见着这样的情形,觉得还是应该去弄懂为啥要这么复杂的声明。在这里记录一下自己的一些心得吧。
首先上代码吧。
public class Shape implements Comparable<Shape>{
protected int value = 0;
@Override
public int compareTo(Shape o) {
return this.value - o.value;
}
}
public class Square extends Shape{
public Square() {super(); value = 1;}
}
public class Circle extends Shape{
public Circle() {super(); value = 2;}
}
public class Test {
public static void main(String[] args) {
Square square = new Square();
Circle circle = new Circle();
GregorianCalendar c = null;
int compare = compare(circle, square);
System.out.println(compare);
// Demo<Square> de = null;
// Demo<GregorianCalendar> demo = null;
}
class Demo<T extends Comparable<T>>{}
public static <AnyType extends Comparable<AnyType>> int compare(AnyType a1, AnyType a2) {
return a1.compareTo(a2);
}
public static <AnyType extends Comparable<AnyType>> AnyType findMax(AnyType[] arr){
int maxIndex = 0;
for(int i = 0; i < arr.length; ++i) {
if(arr[i].compareTo(arr[maxIndex]) > 0) {
maxIndex = i;
}
}
return arr[maxIndex];
}
}
亲测在class声明添加泛型限定时,如果Shape父类实现了Comparable<Shape>方法,则子类Circle通过继承Shape,会实现Comparable<Shape>。需要用泛型的类如果没有后面的<? super T>来修饰,而是简单的<T>,如这里的Demo类,那么用Demo<Circle>来声明类型时会报错。因为Circle只是Comparable<Shape>的子类而不是Comparable<Circle>的子类。
但对于泛型方法,这一要求似乎没有这么严格,如这里的compare方法,传入的是Circle和Squre类型,按理来说它们都是Comparable<Shape>的实现类,而不是Comparable<Circle>, Comparable<Square>的实现类。但它们却能够通过编译。检测它们的类型发现都被转成了Shape,说明虽然声明时是<T>,但编译器自动识别出了T为Shape而不是Circle或Square
不过我觉得对于以后见到父类实现 XX<父类>,子类继承通过继承父类实现 XX<父类> 这样的情形,在需要将他们作为泛型类型传入的时候(不管是类中的泛型类型还是泛型方法中的泛型类型),都用 <T extends XX<? super T>>这样的泛型限定来声明更合理。