在Java中的泛型详解(一)这篇博客中,我详细讲解了一下泛型的概念,擦除机制,泛型的上界以及泛型方法Java中的泛型详解(一),这篇博客将着重讲解一下泛型中另一个较为重要的知识——通配符,我们学习泛型的主要目的是为了后期学习数据结构的时候看懂源码,能够了解每一种数据结构背后是如何实现的从而深入掌握数据结构。
什么是通配符
**?**在泛型中就是一种通配符的符合,在泛型类传参的时候,传入的参数是什么类型我们就只能对这种数据类型进行操作,而通配符一般说明传入的参数是不确定的,这样操作起来的时候会显得更加灵活。
分类
通配符和泛型不同,泛型只有上界,而通配符既有上界也有下界,每一种对应的语法不同且使用的场景也有所区别;下面我们将用代码来分别介绍他们的区别。
代码如下:
在这里插入代码片class Food {
}
class Fruit extends Food{
}
class Apple extends Fruit {
}
class Banana extends Fruit {
}
class Plate<T> {
public T plate;
public T getPlate() {
return plate;
}
public void setPlate(T plate) {
this.plate = plate;
}
}
其中Plate是一个泛型类,类中有两个方法,一个是设置成员变量,一个是获取成员变量。
通配符的上界
语法
这里是引用<? extends 上界>
这里的通配符?表示传入进来的类必须是上界本身或者上界的子类
public class Test {
public static void main(String[] args) {
Plate<Apple> plate = new Plate<>();
plate.setPlate(new Apple());
fun(plate);
Plate<Banana> plate1 = new Plate<>();
plate1.setPlate(new Banana());
fun(plate1);
Plate<Food> plate2 = new Plate<>();
fun(plate2);
}
public static void fun(Plate<? extends Fruit> plate) {
plate.setPlate(new Apple());
plate.setPlate(new Banana());
plate.setPlate(new Fruit());
Fruit fruit = plate.getPlate();
}
}
该代码的主要功能是在main方法里面调用fun方法,fun方法中的参数是一个通配符的上界,然后进行修改数据和读取数据的操作。
注意:
- fun方法中通配符的上界是Fruit,而Food是Fruit的父类,所以fun方法不能接受Food类型的变量,故注释1处报错;
- fun方法接受的类型都是Fruit本身或者Fruit的子类,此时传入的类型并不能确定,用fun方法中的plate对象调用setPlate方法进行修改数据并不知道类型,故注释2处报错;
- 虽然不知道fun方法接受的类型,但是知道他是Fruit本身或者Fruit的子类,所以可以使用plate对象调用getPlate方法来获取对象,获取的对象用Fruit定义的变量接受(这里相当于向上转型),故注释3处编译通过;
总结:通配符的上界不能用来写入数据,但是可以用来读取数据
通配符的下界
语法
这里是引用<? super 下界>
这里的通配符?表示传入进来的类必须是下界本身或者下界的父类
public class Test {
public static void main(String[] args) {
Plate<Fruit> plate = new Plate<>();
plate.setPlate(new Fruit());
fun(plate);
Plate<Food> plate1 = new Plate<>();
fun(plate1);
Plate<Apple> plate2 = new Plate<>();
fun(plate2);
}
public static void fun(Plate<? super Fruit> plate) {
plate.setPlate(new Apple());
plate.setPlate(new Banana());
plate.setPlate(new Fruit());
plate.setPlate(new Food());
Fruit fruit = plate.getPlate();
}
}
该代码的主要功能是在main方法里面调用fun方法,fun方法中的参数是一个通配符的上界,然后进行修改数据和读取数据的操作。
注意:
- fun方法中通配符的下界是Fruit,只能接受Fruit和Fruit的父类的类型,Apple是其子类,故注释1处报错;
- fun方法接受的都是Fruit或者其父类,plate对象调用setPlate方法时可写入Fruit及其子类类型的数据,故注释2处前三行代码不报错,但new Food()时报错;
- fun方法接受的都是Fruit或者其父类,类型不能确定,不能使用Fruit类型接受setPlate方法所返回的值;
总结:通配符的下界不能用来读取数据,但是可以用来写入数据(写入时只能写入通配符本身或者其子类)。