java 教程——泛型,java 零基础教学视频
当?selfMap<Number> 作为函数参数时,该如何传一个?selfMap<Integer> 呢?
这个时候?extends 通配符 就起作用了,我们可以这么写,代码如下:
package test;
import java.lang.reflect.Field;
import java.util.Arrays;
public class changeData {
public static void main(String[] args) {
selfMap<Integer> sf = new selfMap<>(1, 2);
System.out.println(add(sf));
}
static int add(selfMap<? extends Number> selfMap){
Number oneValue = selfMap.getOne();
Number twoValue = selfMap.getTwo();
return oneValue.intValue() + twoValue.intValue();
}
}
class selfMap<T>{
private T one;
private T two;
public selfMap(T one, T two) {
this.one = one;
this.two = two;
}
public T getOne(){
return one;
}
public T getTwo(){
return two;
}
}
你一眼望去可能真看不出有什么区别,可是你细细一看,就会发现我们把?add(selfMap<Number> selfMap) 改成了 add(selfMap<? extends Number> selfMap)
也就是说解决问题的关键在于这么一句申明?<? extends Number> 那它到底是什么呢?
这种使用 <? extends Number> 的泛型定义称之为上界通配符(Upper Bounds Wildcards),即把泛型
类型??T
的上界限定在Number
了。
除了可以传入?Pair<Integer>
类型,我们还可以传入 Pair<Double>
类型,Pair<BigDecimal>
类型等等,因为?Double
和?BigDecimal
都是?Number
的子类。
问题二我们算是解决了,可是问题一我们能解决吗?答案是不可以写成?Number 的子类的,因为你可以传进来的类型太多了,编译器只能确定类型一定是Number
的子类(包括Number
类型本身),但具体类型无法确定。
Set 方法的调用
========
我们把?class selfMap<T> 完善一下,写两个 set 方法玩一下,如下:
class selfMap<T>{
private T one;
private T two;
public selfMap(T one, T two) {
this.one = one;
this.two = two;
}
public T getOne(){
return one;
}
public T getTwo(){
return two;
}
public void setOne(T one) {
this.one = one;
}
public void setTwo(T two) {
this.two = two;
}
}
这个时候我们就可以 调用 里面的 set 方法了,当我们 在 add(selfMap<? extends Number> selfMap) 方法里传入的是?selfMap<? extends Number> selfMap 类型的参数时,根据 “擦试法” 我们可以 明白 真正的 set 方法的写法:
setOne(? extends Number one)
也就是说他需要你传一个?? extends Number 类型的参数,有人说这个简单啊,不就是 Number 的子类吗?,其实不然,简单来解释还是那个原因:Number 子类很多啊,如何保证安全的类型转换呢?很难,所以啊,<? extends Number>
通配符的一个重要限制:方法参数签名 setOne(? extends Number)
无法传递任何Number类型及其
子类型给setOne(? extends Number)
。简单点说就是 :你把 ? extends Number``当做泛型T传入会导致该类的set方法不方便调用。
因此,方法参数类型SelfMap<? extends
Number>
表明了该方法内部只会读取SelfMap
的元素,不会修改SelfMap
的元素(因为无法调用setOne(? extends Number)
方法。换句话说,这是一个对参数SelfMap<? extends
Number>
进行只读的方法(恶意调用setOne(null)
除外)。
使用 extends 限定 T 类型
在定义泛型类型Pair<T>
的时候,也可以使用extends
通配符来限定T
的类型:
public class Pair<T extends Number> { ... }
现在,我们只能定义:
Pair<Number> p1 = null;
Pair<Integer> p2 = new Pair<>(1, 2);
Pair<Double> p3 = null;
因为Number
、Integer
和Double
都符合<T extends Number>
。
非Number
类型将无法通过编译:
Pair<String> p1 = null; // compile error!
Pair<Object> p2 = null; // compile error!
因为String
、Object
都不符合<T extends Number>
,因为它们不是Number
类型或Number
的子类。
小结
使用类似<? extends Number>
通配符作为方法参数时表示:
方法内部可以调用获取
Number
引用的方法,例如:Number n = obj.getFirst();
;方法内部无法调用传入
Number
引用的方法(null
除外),例如:obj.setFirst(Number n);
。
即一句话总结:使用extends
通配符表示可以读,不能写。
使用类似<T extends Number>
定义泛型类时表示:
泛型类型限定为
Number
以及Number
的子类。
评论