泛型上限:? extends
泛型下限:? super
首先需要明确的是泛型上限和下限是定义在方法的参数或者用来声明对象时定义的,如果参数包含一个带有泛型的类,可以用上限或者下限给这个类做相应的限制,如果直接定义在类上会编译错误,比如不会这样定义:
定义泛型类:
class GenericTest<T> {
private T first;
private T last;
public GenericTest(T first, T last) {
this.first = first;
this.last = last;
}
public void setFirst(T first) {
this.first = first;
}
public void setLast(T last) {
this.last = last;
}
public T getFirst() {
return first;
}
public T getLast() {
return last;
}
}
定义父类Fruit:
public class Fruit {
public String name;
public Fruit(String name) {
this.name = name;
}
@Override
public String toString() {
return "{" +
"name='" + name + '\'' +
'}';
}
}
定义两个子类Apple和Banana:
public class Apple extends Fruit{
public Apple(String name) {
super(name);
}
}
public class Banana extends Fruit{
public Banana(String name) {
super(name);
}
}
1. 使用? extends
定义方法:
String testextends(GenericTest<? extends Fruit> p) {
// 用Fruit接收不会有转型出错的风险,无需强制转型
Fruit first = p.getFirst();
//需要强制转型,会有类型转换出错的风险
// 因为像下面的 String result2 = testextends(p2),传进的是GenericTest<Banana> p2,Banana不可以用Apple接收
// Apple first1 = (Apple) p.getFirst();
//无论setFirst的是Fruit、Apple还是Banana,编译都会报错,因为不确定testextends传进来的GenericTest使用了哪种泛型
// 比如调用时是testextends(p2),那p.setFirst(new Apple("Apple 3"))是错误的,因为p2使用了GenericTest<Banana>
// 所以无论setFirst设置的是哪一种数据,都可能会出错,所以有了规定,对于使用了? extends的类,是不可以使用set方法的(不可操作参数带有泛型的方法);
// p.setFirst(new Fruit("Fruit 1"));
// p.setFirst(new Apple("Apple 3"));
// p.setLast(new Banana("Apple 4"));
return p.getFirst().toString() + p.getLast().toString();
}
调用:
//GenericTest的泛型只能是Fruit或者Fruit的子类,也就是说定义了泛型的上限
GenericTest<Fruit> p0 = new GenericTest<>(new Apple("Fruit 1"), new Apple("Fruit 2"));
GenericTest<Apple> p1 = new GenericTest<>(new Apple("Apple 1"), new Apple("Apple 2"));
GenericTest<Banana> p2 = new GenericTest<>(new Banana("Banana 1"), new Banana("Banana 2"));
String result0 = testextends(p0);
String result1 = testextends(p1);
String result2 = testextends(p2);
System.out.println("result1 = "+result0);
System.out.println("result2 = "+result2);
System.out.println("result2 = "+result2);
测试结果:
2.使用? super
定义BigApple继承Apple,即BigApple是Apple的子类,而Apple是Fruit的子类
public class BigApple extends Apple{
public BigApple(String name) {
super(name);
}
}
定义方法:
1.? super后面跟的是最小的类型
//? super BigApple
String testSuper(GenericTest<? super BigApple> p) {
// 和? extend一样,调用get方法都需要强制转型,都有转型出错的风险
// 因为不确定testSuper(GenericTest<? super BigApple> p)被调用时是哪种类型,所以会有转型出错的风险
// Fruit first0 = (Fruit) p.getFirst();
// Apple first1 = (Apple) p.getFirst();
// BigApple first2 = (BigApple) p.getFirst();
// setFirst的是Fruit或者Apple,编译都会报错
// 只有传入是BigApple类型才不会报错
// 因为不确定testSuper(GenericTest<? super BigApple> p)被调用时是哪种类型,
// 而getFirst()是可以用子类以上的全部类型来接收的,如果setFirst不做规定,很可能会出现转型失败
// 所以setFirst只能传入BigApple类型
// p.setFirst(new Fruit("Fruit 1"));
// p.setFirst(new Apple("Apple 1"));
p.setFirst(new BigApple("BigApple 01"));
p.setLast(new BigApple("BigApple 02"));
return p.getFirst().toString() + p.getLast().toString();
}
调用:
//GenericTest的泛型只能是BigApple或者BigApple的父类,也就是说定义了泛型的下限
GenericTest<Fruit> p00 = new GenericTest<>(new Fruit("Fruit 1"), new Fruit("Fruit 2"));
GenericTest<Apple> p01 = new GenericTest<>(new Apple("Apple 1"), new Apple("Apple 2"));
GenericTest<BigApple> p02 = new GenericTest<>(new BigApple("BigApple 1"), new BigApple("BigApple 2"));
String result00 = testSuper(p00);
String result01 = testSuper(p01);
String result02 = testSuper(p02);
System.out.println("result00 = "+result00);
System.out.println("result01 = "+result01);
System.out.println("result02 = "+result02);
结果:
2..? super后面跟的是最大的类型
//? super Fruit
String testSuper2(GenericTest<? super Fruit> p) {
// 和? extend一样,调用get方法都需要强制转型,都有转型出错的风险
// 因为不确定testSuper(GenericTest<? super Fruit> p)被调用时是哪种类型,所以会有转型出错的风险
Fruit first0 = (Fruit) p.getFirst();
// 只能传入Fruit及Fruit的子类
p.setFirst(new Apple("Apple 01"));
p.setLast(new Banana("Banana 02"));
p.setLast(new Fruit("Fruit 02"));
return p.getFirst().toString() + p.getLast().toString();
}
调用:
GenericTest<Fruit> fruitGenericTest = new GenericTest<>(new Fruit("123"),new
Fruit("456"));
System.out.println(testSuper2(fruitGenericTest));
结果:
总结:1.使用了?extend的方法,不可以在方法内调用类的参数带有泛型的方法,也就是上述类的set方法不可用,并且调用get方法需要强制转型,有转型出错风险
2.使用了?super的方法,方法内再调用类的set方法的话,泛型只能是?super后面跟的类或者它的子类,而get方法可以用所有的父类类型来接收,但是也需要强制转型,也会有转型出错的风险