前言
关于java的泛型一开始只学习了<T> 这一种写法。但是到了jdk8的时候由于函数式接口,接触到了很多很不一样的泛型格式,且不易理解,这对学习及使用产生了很大的困扰。
以下将依次对<T>,<?>,<? extends T> ,<? super T>这些格式做详细说明,并提供一些常见的例子以做参考。
<T>
中文名叫占位符,这是最简单的泛型格式。
如下例1,我们定义了一个盘子类,内部维护着一个属性,但是它的类型是泛型,意味着你可以在使用的时候再定义它的具体类型;
- 例1:
public class Plate<T> {
private T t;
public T get() {
return this.t;
}
public void set(T t) {
this.t = t;
}
}
如例2,我们在使用的时候再定义具体的类型。applePlate里面就可以放Apple实例,bananaPlate里面可以存放Banana实例。
- 例2
// 装苹果的盘子
Plate<Apple> applePlate=new Plate<>();
// 装香蕉的盘子
Plate<Banana> bananaPlate=new Plate<>();
所以(T)占位符的意思就是:
在类定义的时候不确定具体类型,可以用一个T来代表一个未确定的类型,而在使用的时候可以指定为任意类型
- 使用泛型的好处
显而易见,如果没有泛型我就需要根据实际情况定义好多个类,装苹果的,装香蕉的,西瓜的。有了泛型我只需要定义一次盘子类就够了,把变化的属性定义成泛型在使用的时候自动生成。封装了不变的(盘子),抽离了变化的(具体的水果),符合开闭设计。
<?>
- 定义:
?:通配符;它与占位符不是同一层次的概念,不出现在类定义中,应该说它说占位符的扩展,为了解决占位符无法解决的一些问题。
在说明 <?> 的作用之前,我们要先看一下占位符的使用有哪些不完美的地方。
- 例3
/*
* 假定我们有Fruit(水果类),及其派生类 Apple,Bnana
*/
// java的多态机制
Fruit fruit=new Apple();
Plate<Apple> applePlate = new Plate<>();
// 类型不同,编译直接不通过
Plate<Fruit> fruitPlate = applePlate;
如上第一行代码我们都知道,基于多态的设计,java允许将子类型的实例赋给父类型引用。但是第三行的代码编译不通过的是因为编译器的逻辑是:
- 苹果 IS-A 水果