问题1:extends和super的区别

泛型

一般的类和方法,只能使用具体类型:要么是基本类型,要么是自定义类型。如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。

泛型的诞生?为了更安全友好的使用容器类 : 用来指定容器要持有什么类型的对象,而且由编译器来保证类型的正确性。

1、概述
  • 术语:适用于许多许多的类型;
  • 本质:实现类型参数化的概念,使代码可以应用于多种类型;
  • 核心:告诉编译器想使用什么类型(指定具体类型参数或对其进行限制),然后编译器帮你处理一切细节(类型安全检查等);
  • 泛型初衷
    (1) 希望类或方法具备最广泛的表达能力,即通过解耦类或方法与所使用的类型之间的约束;
    (2) 对容器类而言,泛型在保证容器类可以存储任何类型对象的同时,又保证了容器类一旦声明自己将要保存的元素类型时,就不可再保存其他类型了,例如:
ArrayList<Fruit> list = new ArrayList<Fruit>();

fruits.add(new Fruit());     // OK
fruits.add(new Apple());     // OK
fruits.add(new Orange());     // OK

fruits.add(new Object());     // Error

上述代码表明了该容器只能保存 Fruit类型 的对象,由于 Apple 也是一种 Fruit,所以其也可以保存 Apple类型 对象,但对于不属于 Fruit类型 的对象,编译器杜绝将其放入列表中。

简单地说:
泛型 = 编译时的类型检查 + 编译时的类型擦除(编译器插入 checkcast 等) + 运行时的自动类型转换。
所以,我们在理解和应用泛型时,一定要从 编译期 和 运行时 两个视角去分析。

2、定义与语法
  • 泛型类(参数化类)
public class Holder<T>{}
  • 泛型接口(参数化接口)
public interface Generator<T>{}
  • 泛型方法(参数化方法;所在类可以是泛型类,也可以不是;能够独立于类而产生变化;细粒度)
public <T> void f(T x){}
3、extends 与 super 的区别?

协变与逆变
逆变与协变用来描述类型转换(type transformation)后的继承关系,其定义:如果 A,B 表示类型,f(⋅)表示类型转换,≤ 表示继承关系(比如,A ≤ B 表示A是B的子类);

  • f(⋅) 是逆变(contravariant)的,当 A≤B 时有 f(B)≤f(A) 成立;
  • f(⋅) 是协变(covariant)的,当 A≤B 时有 f(A)≤f(B) 成立;
  • f(⋅) 是不变(invariant)的,当 A≤B 时上述两个式子均不成立,即f(A)与f(B)相互之间没有继承关系。

(1)泛型
  令f(A) = ArrayList<A>,那么f(⋅) 是逆变、协变还是不变的呢?如果是逆变,则ArrayList<Integer>是ArrayList<Number>的父类型;如果是协变,则ArrayList<Integer>是ArrayList<Number>的子类型;如果是不变,二者没有相互继承关系。由于实际上ArrayList<Number>和ArrayList<Integer>无关,所以泛型是不变的。

(2)数组
令f(A) = A[],容易证明数组是协变的:
Number[] numbers = new Integer[3];

  • <? extends >实现了泛型的协变
 ArrayList<? extends Apple> l3 = new ArrayList<>();
 ArrayList<? extends Fruit> l4 = new ArrayList<>();
 l4 = l3;

对于ArrayList<? extends Apple>类型,我们知道其表示某种具体类型(只是没有确定下来),但是无论其具体指的是ArrayList<Apple>类型还是ArrayList<Jonathan>类型都是可以赋给ArrayList<? extends Fruit>类型的引用的,反之则不可以。因此,我们可以认为ArrayList<? extends Fruit>类型是ArrayList<? extends Apple> 类型的父类型,故<? extends>实现了泛型的协变。

  • <? super>实现了泛型的逆变
  ArrayList<? super Apple> l1 = new ArrayList<>();
  ArrayList<? super Fruit> l2 = new ArrayList<>();
  l1 = l2;

对于 ArrayList<? super Fruit>类型,我们知道其表示某种具体类型(只是没有确定下来),但是无论其具体指的是ArrayList<Fruit>类型还是ArrayList<Object>类型都是可以赋给ArrayList<? super Apple>类型的引用的,反之则不可以。因此,我们可以认为ArrayList<? super Apple>类型是ArrayList<? super Fruit>类型的父类型,故 <? super>实现了泛型的逆变。

引用链接:https://blog.csdn.net/justloveyou_/article/details/52420071