自学内容网 自学内容网

回顾泛型,学习通配符

1.前置知识回顾:


       在学习数据结构的预备知识的时候,我们已经初步认识了泛型,所谓泛型就是适用于很多类型,从代码来说就是对类型实现了参数化.

        泛型的主要目的:就是指定当前的容器,要持有什么类型的对象。让编译器去做检查。此时,就需要把类型,作为参数传递。需要什么类型,就传入什么类型. 

        语法:

        其中,<T>代表占位符,表示当前的类是一个泛型类

        class 泛型名称 <类型参数列表> {   }

        class 泛型名称<T1,T2,T3...>

        class 泛型名称<类型参数列表>extends 继承类 {  }

        class 泛型名称<T1,T2,T3...>extends parentClass<T>{}

        一些规范:

E 表示 Element

K 表示 Key

V 表示 Value

N 表示 Number T 表示 Type

S, U, V 等等 - 第二、第三、第四个类型

         泛型类的使用:

        我们在第一个<>里面写上类型即可

泛型类名<引用数据类型> 对象名 = new 泛型类名<引用数据类型>();

        泛型的上界:

        比如:

class TestGneric <T extends Number>{}这个类表示的泛型类, T一定是Number或者Number的子类 

        泛型方法:

方法限定符 <类型参数列表> 返回值类型 方法名称(形参列表) {...} 

 

这个玩意就是我们在普通类里面写一个泛型方法我们限定T是要实现Comparable 接口的类型

访问修饰限定符

<T extends 接口<T>> T 方法名 (T 参数) {}  

         擦除机制:

        基本上就是,我们在编译的时候,把泛型擦成了Object

2. 通配符   

        2.1 通配符的概念

        ? 用于在泛型的使用,即为通配符

        ?表示可以接收所有的泛型类型,但是又不能够让用户随意修改。

把T改成?就不报错了,因为这里的 T 是一个未声明的类型参数。编译器不知道 T 是什么类型,因为它没有在 fun 方法的上下文中被定义。如果你想让 fun 方法接受任何类型的 Message,所以使用泛型通配符(?)。

        具体代码:

package 泛型进阶;


//TODO 通配符
class Message<T> {
    private T message;

    public T getMessage() {
        return message;
    }

    public void setMessage(T message) {
        this.message = message;
    }
}
public class Test {

    public static void main1(String[] args) {
        Message<String> message = new Message<>() ;
        message.setMessage("小白");
        fun(message);
        Message<Integer> message1 = new Message<>();
        message1.setMessage(10);
        fun(message1);
    }
    public static void fun(Message<?> temp){//通配符接受任意类型,
        System.out.println(temp.getMessage());
//        temp.setMessage(23);//无法设置,因为类型是不确定的
    }
}

        2.2 通配符的上下界    

        先介绍几个类以及它们之间的关系

通配符的上下界语法:

        ? extends 类:设置通配符上限

        ? super 类:设置通配符下限

        1> 通配符的上界

         上界,也就是最多不能超过的意思,也就是说<=父类

        Apple,Banana都是Fruit的子类,因此可以在fun里面进行传参.

注意一个点:

        我们的通配符表示接受任意类型,但是传进来的参数类型是不确定的,因此我们不能修改参数.

        也就是此时无法在fun函数中对temp进行添加元素,因为temp接收的是Fruit和他的子类,此时存储的元素应该是哪个子类无法确定。所以添加会报错!但是可以获取元素。

        因此: 通配符的上界,不能进行写入数据,只能进行读取数据。
 

        具体代码:

package 泛型进阶;

import java.util.ArrayList;

class Food {

}
class Fruit extends Food {

}
class Apple extends Fruit {

}
class Banana extends Fruit {

}
class Plate<T> { // 设置泛型
    private T message ;

    public T getMessage() {
        return message;
    }

    public void setMessage(T message) {
        this.message = message;
    }

}
public class Test2 {

    public static void main(String[] args) {
        //App
        Plate<Apple> plate = new Plate<>();
        Plate<Banana> plate2 = new Plate<>();

        fun(plate);
        fun(plate2);
    }


 //TODO 通配符的上界
    public static void fun(Plate<? extends Fruit> temp){
    // 此时使用通配符"?"描述的是它可以接收任意类型,但是由于不确定类型,所以无法修改
        //temp.setMessage(new Banana()); //仍然无法修改!
        //temp.setMessage(new Apple()); //仍然无法修改!
        Fruit fruit = temp.getMessage();//向上转型
        System.out.println(fruit);
    }
}

        2> 通配符的下界

                ​​​​​​

        下界,也就是>=的意思,不能小于父类的意思

        Food是Fruit的父类,因此可以调用fun2进行传参

        这里注意一个点:

        通配符的下界,不能进行读取数据,只能写入数据。

        具体代码:

package 泛型进阶;

import java.util.ArrayList;

class Food {

}
class Fruit extends Food {

}
class Apple extends Fruit {

}
class Banana extends Fruit {

}
class Plate<T> { // 设置泛型
    private T message ;

    public T getMessage() {
        return message;
    }

    public void setMessage(T message) {
        this.message = message;
    }

}
public class Test2 {


    public static void main2(String[] args) {
        ArrayList<Integer> a = new ArrayList<>();
        Plate<Fruit> plate = new Plate<>();
        Plate<Food> plate2 = new Plate<>();

        fun2(plate);
        fun2(plate2);
    }
    //TODO 通配符的下界

    public static void fun2(Plate<? super Fruit> temp) {
        temp.setMessage(new Apple());
        temp.setMessage(new Banana());


        //Fruit fruit = (Fruit)temp.getMessage();//传过来的都是父类所以要强转
    }

}

        小总结:

1. ?一般作为参数类型使用,T一般用于泛型类,泛型方法的定义来使用.

2. ? 一般不晓得确切类型,因此只能读不能写(修改).T一般晓得确切类型,可以读和修改.

3. 通配符的下界,不能进行读取数据,只能写入数据。通配符的上界,不能进行写入数据,只能进行读取数据。


原文地址:https://blog.csdn.net/2201_75880772/article/details/144326957

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!