写点什么

java 教程——泛型,java 零基础教学视频

  • 2021 年 11 月 10 日
  • 本文字数:1744 字

    阅读完需:约 6 分钟

当?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),即把泛型


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


类型??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;


因为NumberIntegerDouble都符合<T extends Number>


Number类型将无法通过编译:


Pair<String> p1 = null; // compile error!


Pair<Object> p2 = null; // compile error!


因为StringObject都不符合<T extends Number>,因为它们不是Number类型或Number的子类。

小结

使用类似<? extends Number>通配符作为方法参数时表示:


  • 方法内部可以调用获取Number引用的方法,例如:Number n = obj.getFirst();

  • 方法内部无法调用传入Number引用的方法(null除外),例如:obj.setFirst(Number n);


即一句话总结:使用extends通配符表示可以读,不能写。


使用类似<T extends Number>定义泛型类时表示:


  • 泛型类型限定为Number以及Number的子类。

评论

发布
暂无评论
java教程——泛型,java零基础教学视频