打字猴:1.700447318e+09
1700447318 子类的doStuff方法返回值的类型比父类方法要窄,此时doStuff方法就是一个协变方法,同时根据Java的覆写定义来看,这又属于覆写。那逆变是怎么回事呢?代码如下:
1700447319
1700447320 class Base{
1700447321
1700447322 public void doStuff(Integer i){
1700447323
1700447324 }
1700447325
1700447326 }
1700447327
1700447328 class Sub extends Base{
1700447329
1700447330 public void doStuff(Number n){
1700447331
1700447332 }
1700447333
1700447334 }
1700447335
1700447336 子类的doStuff方法的参数类型比父类要宽,此时就是一个逆变方法,子类扩大了父类方法的输入参数,但根据覆写定义来看,doStuff不属于覆写,只是重载而已。由于此时的doStuff方法已经与父类没有任何关系了,只是子类独立扩展出的一个行为,所以是否声明为doStuff方法名意义不大,逆变已经不具有特别的意义了,我们来重点关注一下协变,先看如下代码是否是协变:
1700447337
1700447338 public static void main(String[]args){
1700447339
1700447340 Base base=new Sub();
1700447341
1700447342 }
1700447343
1700447344 base变量是否发生了协变?是的,发生了协变,base变量是Base类型,它是父类,而其赋值却是子类实例,也就是用窄类型覆盖了宽类型。这也叫多态(Polymorphism),两者同含义,在Java世界里“重复发明”轮子的事情多了去了。
1700447345
1700447346 说了这么多,下面再来想想泛型是否也支持协变和逆变,答案是:泛型即不支持协变,也不支持逆变。很受伤是吧?为什么会不支持呢?
1700447347
1700447348 (1)泛型不支持协变
1700447349
1700447350 数组和泛型很相似,一个是中括号,一个是尖括号,那我们就以数组为参照对象,看如下代码:
1700447351
1700447352 public static void main(String[]args){
1700447353
1700447354 //数组支持协变
1700447355
1700447356 Number[]n=new Integer[10];
1700447357
1700447358 //编译不通过,泛型不支持协变
1700447359
1700447360 List<Number>ln=new ArrayList<Integer>();
1700447361
1700447362 }
1700447363
1700447364 ArrayList是List的子类型,Integer是Number的子类型,里氏替换原则(Liskov Substitution Principle)在此处行不通了,原因就是Java为了保证运行期的安全性,必须保证泛型参数类型是固定的,所以它不允许一个泛型参数可以同时包含两种类型,即使是父子类关系也不行。
1700447365
1700447366 泛型不支持协变,但可以使用通配符(Wildcard)模拟协变,代码如下所示:
1700447367
[ 上一页 ]  [ :1.700447318e+09 ]  [ 下一页 ]