泛型的限定和通配符的使用

本文详细介绍了Java中泛型通配符的基本使用,包括无界通配符、上限和下限的用法。通过实例展示了如何在方法参数中应用这些通配符,以及它们在读取、写入操作上的限制。此外,还提出了PECS原则(Producer Extends, Consumer Super),指导如何根据方法功能选择合适的通配符。
摘要由CSDN通过智能技术生成

通配符基本使用

泛型的通配符:不知道使用什么类型来接收的时候,此时可以使用?,?表示未知通配符。

当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示。但是一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。

通配符只能遍历、删除,不能添加修改。
示例一   通配符参数
在这里插入图片描述
示例二  通配符变量

在这里插入图片描述


public static void main(String[] args) {
    Collection<Intger> list1 = new ArrayList<Integer>();
    getElement(list1);
    Collection<String> list2 = new ArrayList<String>();
    getElement(list2);
}
public static void getElement(Collection<?> coll){}
//?代表可以接收任意类型

tips:泛型不存在继承关系 Collection list = new ArrayList();这种是错误的。

通配符高级使用----受限泛型

之前设置泛型的时候,实际上是可以任意设置的,只要是类就可以设置。但是在JAVA的泛型中可以指定一个泛型的上限下限

泛型的上限

  • 格式类型名称 <? extends A类 > 对象名称
  • 意义只能接收该类型及其A类子类

泛型的下限

  • 格式类型名称 <? super B类 > 对象名称

  • 意义只能接收该类型及其B类父类型

  • <?>无限定的通配符, 是让泛型能够接受未知类型的数据
  • <? extends E> 有上限通配符,能够接受指定类及其子类类型的数据,E就是该泛型的上边界

注意:这里不仅继承了父类E的子类,也可以代指显现了接口E的类

  • <? super E>:有下限的通配符。能够指定其父类类型的数据,E就是该泛型类型的下边界。

注意:你可以为一个泛型指定上边界或者下边界,但是不能同时指定上下边界

比如:现已知Object类,String 类,Number类,Integer类,其中Number是Integer的父类
比如:现已知Object类,String 类,Number类,Integer类,其中Number是Integer的父类


public static void main(String[] args) {
    Collection<Integer> list1 = new ArrayList<Integer>();
    Collection<String> list2 = new ArrayList<String>();
    Collection<Number> list3 = new ArrayList<Number>();
    Collection<Object> list4 = new ArrayList<Object>();
    
    getElement(list1);
    getElement(list2);//报错
    getElement(list3);
    getElement(list4);//报错
  
    getElement2(list1);//报错
    getElement2(list2);//报错
    getElement2(list3);
    getElement2(list4);
  
}
// 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
public static void getElement1(Collection<? extends Number> coll){}
// 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
public static void getElement2(Collection<? super Number> coll){}

泛型的修饰符的下限

通过super关键字,在定义类的时候修饰泛型,表明泛型参数只能是Furit的子类

public class Banan <H,E extends Furit,L extends Furit> extends Furit {

    private H fromPlace;

    private L toPalce;

    public List<H>  queryFrom(int fromID){
        return new ArrayList<>();

    }

    public List<L>  queryToPlace(int fromID){
        return new ArrayList<>();
    }

}

泛型类的使用
定义泛型类的实现只能是Furit的子类

public class GenericTest {

    public static void main(String[] args) {
        Banan<String,Banan,Banan>  banan = new Banan();
        banan.queryFrom(1);
		}
}

多个限定符的绑定

上面我们讲了,有关绑定限定的用法,其实我们可以同时绑定多个绑定,用&连接,比如:

public static <T extends Fruit&Serializable> String getFruitName(T t){
    return t.getName();
}

再加深下难度,如果我们有多个泛型,每个泛型都带绑定,那应该是什么样子的呢:

public static <T extends Fruit&Serializable> String getFruitName(T t){
    return t.getName();
}

大家应该看得懂,稍微讲一下:这里有两个泛型变量T和U,将T与Comparable & Serializable绑定,将U与Runnable绑定。
好了,这部分就讲完了,下面讲讲有关通配符的用法。

?与T的区别

大家可能会有疑问,那无边界通配符?与泛型变量T有什么区别呢?
答案是:他们俩没有任何联系!!!!!
泛型变量T不能在代码用于创建变量,只能在类,接口,函数中声明以后,才能使用。
比如:

public class Box<T> {
   public T get(){
	   …………
   };
   public void put(T element){
	   …………
   };
}

而无边界通配符?则只能用于填充泛型变量T,表示通配任何类型!!!!再重复一遍:?只能用于填充泛型变量T。它是用来填充T的!!!!只是填充方式的一种!!!
比如:

//无边界通配符填充
Box<?> box;
//其它类型填充
Box stringBox;
(3)、通配符只能用于填充泛型变量T,不能用于定义变量
大家一定要记得,通配符的使用位置只有:

Box<?> box;
box = new Box<String>();

即填充泛型变量T的位置,不能出现在后面String的位置!!!!
下面的第三行,第四行,都是错误的。通配符不能用于定义变量。

再次强调,?只能出现在Box<?> box;中,其它位置都是不对的。

通配符下限

通配符下限 参数 ,参数可以接受其子和其本身的类,遍历类型只能为Object <? super CompanPerson>通配符告诉编译器我们在处理一个类型CompanPerson的类型及其父类型, 但我们不知道这个父类型究竟是什么。因为没法确定,为了保证类型安全,我们就不允许往里面加入任何这种父类型的数据。同时遍历也不知道父类型是什么,因此 get的也是Object。

参数示例

通配符参数
在这里插入图片描述

通配符上限

通配符上限,只能遍历,不能添加,修改,但是可以删除 <? extends Fruit>通配符告诉编译器我们在处理一个类型CompanPerson的类型及其子类型, 但我们不知道这个子类型究竟是什么。因为没法确定,为了保证类型安全, 我们就不允许往里面加入任何这种类型的数据。但是可以get到CompanPerson类型的元素对象。通配符上限不允许添加修改,可以删除,只能遍历

https://www.cnblogs.com/storml/p/7997845.html
在这里插入图片描述

通配符上下限使用总结

/**
*
* https://www.cnblogs.com/storml/p/7997845.html
* (3) PECS法则
*
* 0.不管通配符上限还是下限,不能添加,子类型
* 总结<? extends T>/<? super T>通配符的特征,我们可以得出以下结论:
*
* 1. 如果你想在方法中从input参数里获取数据,使用<? extends T>通配符 , 只能遍历,删除
*
* 2. 如果你想在方法中把对象写入一个input参数中,使用<? super T>通配符,不能添加T 的子类型
*
* 3. 如果你既想存,又想取,那就别用通配符
*
* PECS指“Producer Extends,Consumer Super”。换句话说,如果方法中的参数表示一个生产者,就使用<? extends T>;如果它表示一个消费者,就使用<? super T>。
*/

在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值