问题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