关于java泛型初阶的详细介绍,请看博客:
小编花了很多时间认真打磨的,涉及很多细节,讲解清晰,只要能学到东西,没有点赞啥的我都很高兴的(●'◡'●)。
关于泛型的进阶,我们主要聚焦讲解:
示例:
class Generics<T> {
private T message;//泛型成员变量
public T getMessage() {//泛型方法,获取泛型数据
return message;
}
public void setMessage(T message) {//泛型方法,设置泛型数据
this.message = message;
}
}
public class Test {
public static void main(String[] args) {
Generics<String> tes = new Generics<>();//new一个刚才定义的泛型类
tes.setMessage("灰太狼大王");
printFun(tes);
}
private static void printFun(Generics<String> tes) {//这个静态方法要在静态main方法中打印信息
System.out.println(tes.getMessage());
}
}
执行结果:
相信这个肯定难不倒大家。
我们在原来的程序基础上做一些更改:
此时,编译器报错了:
没错,printFun方法的参数类型是Generics<String>与传入的Generics<Integer>不匹配,编译器报错。
这就很麻烦了,难道还要重新写一个与Integer适配的方法吗?这样效率未免太低。
为了解决上面的问题,通配符(?)就派上用场了,我们只需要对printFun方法做一个小的更改:
回过头来,main方法,就可以执行了:
如果想要限制通配符接收的范围,可以对通配符的接收范围进行限制,这也是接下来要讲的。
通配符的上界和泛型的上界语法和作用类似,如图先看一下这几个类的继承关系:
如果我们要定义通配符的上界为Fruit,可以这样写:
此时的fun方法,传递的参数类型,只能是继承图中,三角型框中的一种,否则编译器会报错:
这个Plate类以及各种子类,先了解一下我的定义,马上要用到,不然看的一头雾水:
class Food { public void name(){ System.out.println("食物"); } } class Fruit extends Food { public void name(){ System.out.println("水果"); } } class Apple extends Fruit { public void name(){ System.out.println("苹果"); } } class Banana extends Fruit { public void name(){ System.out.println("香蕉"); } } class Plate<T> { // 设置泛型 private T food;//定义一个泛型类,一定是一个食物,具体是啥还不清楚 public T getPlate() {//返回这个食物类 return food; } public void setPlate(T food) {//更改这个食物类 this.food = food; } }
对于上界通配符,可以对传入的数据进行读取:
执行结果:
从程序中,我们看到,
上界通配符可以:
进行数据读取。
但是:
它不能写入数据!!:
下界和上界关系就恰恰相反,如果我们规定Fruit作为下面这个方法的下界:
那么,只需要用到super关键字:
意思是对于Plate<T>中的T,只能是Fruit或者其超类(也就是父类,叫法不一样而已),简单来讲就是只能传入三角框内的类:
(小臂有点疼,字难看,见谅了(❁´◡`❁))
注意:
下界通配符可以对数据进行修改不过需要强制类型转换,其实就是上面,上界举的fruit例子。
另外,下界通配符是可以对数据进行更改写入的,而上界通配符不可以!!!