【03】泛型限定通配符

(1)一个人只要自己不放弃自己,整个世界也不会放弃你.
(2)天生我才必有大用
(3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟.
(4)做难事必有所得
(5)精神乃真正的刀锋
(6)战胜对手有两次,第一次在内心中.
(7)好好活就是做有意义的事情.
(8)亡羊补牢,为时未晚
(9)科技领域,没有捷径与投机取巧。
(10)有实力,一年365天都是应聘的旺季,没实力,天天都是应聘的淡季。
(11)基础不牢,地动天摇
(12)写博客初心:成长自己,辅助他人。当某一天离开人世,希望博客中的思想还能帮人指引方向.
(13)编写实属不易,若喜欢或者对你有帮助记得点赞+关注或者收藏哦~

泛型限定通配符

1.泛型的继承和子类型

1.1以下泛型类的继承关系不成立

1)给定两种具体的类型AB(例如FruitApple)无论AB是否相关,MyClass<A>MyClass<B>都没半毛钱关系,它们的公共父类是Object.2A父类是B
JavaList<A>
List<A>
Plate<A>不变 它的父类不会是Plate<B>?
因为没有继承关系就不能够强转:
Plate<A> a = plate;3)这个案例属于泛型类型的类型参数T不一样,所以继承关系就不成立。虽然A继承自B,但是当AB类分别作为泛型类的类型参数后,各自泛型类的继承关系就不成立了。

1.2以下泛型类的继承关系成立

在这里插入图片描述

(1)只要泛型类的类型参数T保持数据类型一致,无论子类型如何扩展泛型的类型参数,泛型类的继承关系都是成立的。

(2)泛型类的继承关系代码

package com.generics.demo3.plate;

public interface Plate<T> {

    public void set(T t);

    public T get();

}
package com.generics.demo3.plate;

import java.util.ArrayList;
import java.util.List;

/**
 * @PackageName:com.generics.demo3.plate
 * @ClassName:AIPlate
 * @Description: 泛型类型定义
 * @author:青风百草
 * @date:2020/9/2 10:22
 */
public class AIPlate<T> implements Plate<T> {

    private List<T> items = new ArrayList<>();


    @Override
    public void set(T t) {
        items.add(t);
    }

    @Override
    public T get() {
        int index = items.size() -1;
        if (index >= 0) {
            return items.get(index);
        } else {
            return null;
        }
    }
}

package com.generics.demo3.plate;

/**
 * @PackageName:com.generics.demo3.plate
 * @ClassName:BigPlate
 * @Description:
 * @author:青风百草
 * @date:2020/9/2 10:39
 */
public class BigPlate<T> extends AIPlate<T>{

}

package com.generics.demo3.plate.inheritedclass;

import com.generics.demo3.plate.BigPlate;

/**
 * @PackageName:com.generics.demo3.plate.inheritedclass
 * @ClassName:ColorPlate
 * @Description:
 * @author:青风百草
 * @date:2020/9/2 10:45
 */
public class ColorPlate1<K,T> extends BigPlate<T> {

}

package com.generics.demo3.test;

import com.generics.demo3.fruit.Apple;
import com.generics.demo3.plate.AIPlate;
import com.generics.demo3.plate.BigPlate;
import com.generics.demo3.plate.Plate;
import com.generics.demo3.plate.inheritedclass.ColorPlate1;

/**
 * @PackageName:com.generics.demo02.test
 * @ClassName:Test4
 * @Description:
 * @author:青风百草
 * @date:2020/9/2 10:18
 */
public class Test {

    /*
     *泛型类型继承:ColorPlate1---> BigPlate --->AIPlate --->Plate
     *@Author 青风百草
     *@Description 无论ClorPlate怎么扩展,只要Apple不变,这种泛型类的继承关系还是存在的。
     *@Date 10:58 2020/9/2
     *@Param []
     *@return void
     **/
    public static void test1(){
        Plate<Apple> applePlate1 = new AIPlate<Apple>();
        Plate<Apple> applePlate2 = new BigPlate<Apple>();
        Plate<Apple> applePlate3 = new ColorPlate1<String,Apple>();
    }

    public static void main(String[] args) {
        test1();
    }
}

2.通配符

2.1上界通配符

在这里插入图片描述

(1)上界通配符泛型类的定义方式

Plate <? extends 类型>

(2)上界通配符是为了限定泛型类的类型参数中的数据类型可以是指定类型参数的数据类型的派生类型,即它的子类。这样的好处是方便泛型类型对象赋值。

(3)例如:

Plate<? extends Fruit>这个泛型类的实际类型参数,只能是Fruit类型的子类。

2.2转型方便带来的后遗症

在这里插入图片描述

2.2.1存放数据时的问题

(1)就是泛型对象无法再存放任何的元素。
(2)放null可以。
(3)虽然通过反射能够放数据,但是什么都能放了,安全性就没办法保证。
在这里插入图片描述

2.2.2取出数据时的问题

(1)就不清楚得到的数据具体是什么数据类型。

2.3下界通配符

在这里插入图片描述

(1)下界通配符泛型类的定义方式

Plate <? super 类型>

(2)表示的意思是泛型类的类型参数的数据类型,只能是该类型的父类和基类

(3)例如:

Plate<? super Fruit>这个泛型类的实际类型参数,只能是Fruit类型的父类和基类。

(4)使用下界通配符的后遗症是什么?
在这里插入图片描述

意思就是数据拿出来的时候就不清楚具体是什么数据类型了,只能以限定类的父类或基类Object存放。

2.4非限定通配符

1Plate<?>:这就称作非限定通配符.2)它是一个泛型类型,但是泛型的类型参数数据类型是未知的。
(3)等价于Plate<? extends Object>
2.4.1非限定通配符的副作用

在这里插入图片描述

(1)是即不能写也不能读

2.4.2不能读不能写,那泛型有什么用呢

(1)它可以保证泛型可以检查类型
(2)例如:

List :这种情况不会对数据类型进行安全检查
List<?>:编译器会进行数据类型的安全检查

2.5限定通配符

1Plate<? extends T>:上界限定通配符
(2Plate<? super T>:下界限定通配符
这两种情况统称为限定通配符。
2.5.1上界限定通配符的副作用

在这里插入图片描述

(1)只能读,不能写.

2.5.2下界限定通配符的副作用

在这里插入图片描述

(1)只能写,不能读

3.通配符与泛型有什么关系?

1)因为泛型<T>:如果这样声明,就只能写具体的某一种泛型类型,会遇到数据转型的一个问题,参考1.1的描述,而使用通配符让类型转换变得更灵活。

4.Java泛型的PECS原则

1)如果你只需要从集合中获得类型T,使用<? extends T>通配符
(2)如果你只需要将类型T放到集合中,使用<? super T>通配符
(3)如果你既要获取又要放置元素,则不使用任何通配符。
例如:	List<Apple>4)PECS即Producer extends Consumer super,为了便于记忆。
(a)Producer代表的是生产者,不能写,只能读。
(b)Consumer代表的是消费者,可以写,不能读。

4.1泛型为什么需要PECS原则?

1)提升API的灵活性。即类型转换的灵活性。
(2<?>既不能存又不能取

5.使用通配符的目的是什么?

(1)就一个目的,为了灵活的转型

6.泛型的应用举例

6.1涉及的实体类

(1)Fruit

package com.generics.demo01.fruit;

/**
 *水果
 */
public class Fruit {
	@Override
	public String toString() {
		return "水果";
	}
}

(2)Apple

package com.generics.demo01.fruit;

/**
 * 苹果
 */
public class Apple extends Fruit{

	private int id;

	public Apple(){

	}

	public Apple(int id){
		this.id = id;
	}

	@Override
	public String toString() {
		return "Apple{" +
				"id=" + id +
				'}';
	}
}

(3)Banana

package com.generics.demo01.fruit;

/**
 *香蕉
 */
public class Banana extends Fruit {

	private int id;

	public Banana() {
	}

	public Banana(int id){
		this.id = id;
	}

	@Override
	public String toString() {
		return "Banana{" +
				"id=" + id +
				'}';
	}
}

6.2应用

(1)每一个步骤都是因为前一步骤遇到问题才出现的下一个方法,可以结合代码思考错误原因,为什么用到下一方法来解决问题。

package com.generics.demo3.test;

import com.generics.demo01.fruit.Apple;
import com.generics.demo01.fruit.Banana;
import com.generics.demo01.fruit.Fruit;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @PackageName:com.generics.demo3.test
 * @ClassName:Test2
 * @Description:
 * @author:青风百草
 * @date:2020/9/2 17:07
 */
public class Test2 {

    public static void biz1(){

        //================s1.使用集合实现复制=======================
        List<Apple> src1 = new ArrayList<>();
        src1.add(new Apple(1));
        List<Apple> dest1 = new ArrayList<>(10);
        dest1.add(new Apple(2));
        System.out.println(dest1);
        copy1(dest1,src1);
        System.out.println(dest1);

        //=================s2.使用泛型实现复制======================
        List<Banana> src2 = new ArrayList<>();
        src2.add(new Banana(1));
        List<Banana> dest2 = new ArrayList<>(10);
        dest2.add(new Banana(2));
        //s1.此时已经无法复制,解决办法是使用限定通配符
        //copy1(dest2,src2);
        //s2.使用泛型之后无论是苹果还是香蕉都可以存取了
        copy2(dest2,src2);

        //=================s3.使用通配符实现复制======================

        //s3.但是当我遇到如下情况,当是一个水果盘子的时候,再调用copy1,发现又不能放了,为什么
        List<Fruit> dest3 = new ArrayList<>();
        dest3.add(new Banana());
        //copy2(dest3,src2);
        //使用通配符
        copy3(dest3,src2);

        //==================s4.使用上界与下界通配符结合的方式==============

        List<Fruit> dest4 = new ArrayList<>();
        dest4.add(new Banana());
        //如果泛型限定了泛型类型为Fruit,则List<Banana>无法放入泛型,此处就需要用到上
        // 界限通配限定符来满足这一情况
        //Test2.<Fruit>copy3(dest4,src2);
        Test2.<Fruit>copy4(dest4,src2);

    }

    public static void copy1(List<Apple> desc,List<Apple> src){
        Collections.copy(desc,src);
    }

    //s2.使用泛型
    public static <T> void copy2(List<T> desc, List<T> src){
        Collections.copy(desc,src);
    }

    //s3.使用下界限定通配符
    public static <T> void copy3(List<? super T> desc, List<T> src){
        Collections.copy(desc,src);
    }

    //s4.使用上界限定通配符
    //(1)List<? extends T> src是生产者,可以从里面取数据出来
    //(2)List<? super T> desc是消费者,可以向里面写入数据
    public static <T> void copy4(List<? super T> desc, List<? extends T> src){
        Collections.copy(desc,src);
    }

    public static void main(String[] args) {
        biz1();
    }
}

7.泛型的应用场景

7.1泛型在集合中的使用

在这里插入图片描述

7.2泛型在RxJava中的应用

在这里插入图片描述

8.练习

(1)理解如下写法的含义及区别
在这里插入图片描述

9.打赏鼓励

感谢您的细心阅读,您的鼓励是我写作的不竭动力!!!

9.1微信打赏

在这里插入图片描述

9.2支付宝打赏

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值