首页 百科知识 泛型的子类型与通配符

泛型的子类型与通配符

时间:2022-02-19 百科知识 版权反馈
【摘要】:6.7.4 泛型的子类型与通配符我们知道,抽象类Number是BigDecimal、BigInteger、Byte、Double、Float、Integer、Long 和Short类的超类。对于泛型而言,下列语句是合法的,编译器不会报错。这违背了我们引入泛型的目的。extends Number含义是“未知类型是Number类型或者是其某种子类型”。

6.7.4 泛型的子类型与通配符

我们知道,抽象类Number是BigDecimal、BigInteger、Byte、Double、Float、Integer、Long 和Short类的超类。

根据类型转换规则,子类的对象引用值可以赋给超类类型的变量,如:

对于数组而言,只要数组元素存在继承关系,那么,相应的数组类型也存在继承关系,如:Number是Double、Float、Integer、Long和Short类的超类,那么,数组类型Number[]也是Double[]、Float[]、Integer[]、Long[]和Short[]数组类型的超类,这样就有:

上述赋值语句,编译器不会报错。

对于泛型而言,下列语句是合法的,编译器不会报错。

这里,public void setObject(T object)方法在将具体类型Number传递给类型形参T后,该方法实际上是:public void setObject(Number object),根据方法参数传递规则,setObject (Number object)方法的形参Number object可以接受Number类的子类对象。

虽然抽象类Number是Double、Float、Integer、Long和Short类的超类。但是,泛型Box <Number>不是Box<Double>、Box<Float>、Box<Integer>、Box<Long>、Box<Short>的超类,它们之间没有继承关系。这样,下列代码:

由于numObj是Box<Number>类型,intObj是Box<Integer>类型,Box<Integer>不是Box<Number>的子类,这两个类型没有继承关系,所以,编译错误。

我们用反证法来说明Box<Integer>不是Box<Number>的子类。假设numObj=intObj;语句成立,没有编译错误,那么numObj.setObject(new Double(2.17281728));就能正确执行,因为numObj是Box<Number>类型,可以装入Number类的子类Double型对象,这样,执行Integer iInt=intObj.getObject();就会得到一个Double型对象,而不是Integer型对象。这违背了我们引入泛型的目的。

可见,一般来说,如果Sub是Super的子类型,G是某种泛型,那么,G<Sub>并不是G<Super>的子类型。

Box<Double>、Box<Float>、Box<Integer>、Box<Long>、Box<Short>的超类是什么呢?我们说,Box<?extends Number>是Box<Number>以及Box<Double>、Box<Float>、Box<Integer>、Box<Long>、Box<Short>的超类。

在这里,?是通配符,表示一种未知类型。它常用的两种格式是:

格式1: ?extends上限类型

这样,?extends Number含义是“未知类型是Number类型或者是其某种子类型”。

格式2: ?super下限类型

这样,?super Number含义是“未知类型是Number类型或者是其某种超类型”。

【例6-18】 使用通配符改写例6-17。

程序运行结果:

分析与思考:(1)setObject(Box<?extends T>obj)中的形参Box<?extends T>obj说明实参只能是Box<?extends T>的子类对象,诸如Box<Number>、Box<Integer>、Box<Double>、Box<Float>等类型对象,前提是参数化类型Box<Number>将Number传递给了T。

(2)numObj.setObject(intObj);语句的含义是将intObj盒子的对象取出并作为numObj盒子的对象。

(3)程序加入语句Double doubleO=numObj.getObject();,请读者思考,会出现什么结果?

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈