zoukankan      html  css  js  c++  java
  • 泛型(5)-类型通配符的下限

      除了可以指定通配符的上限之外,Java也允许指定通配符的下限,通配符的下限用<? super 类型>的方式指定,通配符下限的作用于通配符上限的作用恰好相反.

      指定通配符的下限就是为了支持类型型变.比如Foo是Bar的子类,当程序需要一个A<? super Bar>变量时,程序可以将A<Foo>,A<Object>赋值给A<? super Bar>类型的变量,这种方法被称为逆变.

      对于逆变的泛型集合来说,编译器只知道集合元素是下限的父类型,但具体是哪一种父类型则不确定.因此,这种逆变的泛型集合只能向其中添加元素(因为实际赋值的集合元素总是逆变声明的父类),从集合中去元素只能被当成Object类型处理(编译器无法确定取出的到底是哪个父类的对象).

      假设自己实现了一个工具方法:实现将src集合中的元素复制到dest集合的功能,因此dest集合可以保存src集合中的所有元素,所以dest集合元素的类型应该是src集合元素类型的父类.

      对于上面的copy()方法,可以这样理解两个集合参数之间的依赖关系:不管src集合元素的类型是什么,只要dest的集合元素的类型与前者相同或者是前者的父类即可.

    package com.j1803.Type_wildcards;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;
    public class MyUtils {
       //下面的dest集合元素的类型必须与src集合元素的类型相同,或者是其父类
    public static <E> E copy(Collection<? super E>dest,Collection<E>src){
    E last=null;
    for(E ele:src){
    last=ele;
    //逆变的泛型集合添加元素是安全的
    dest.add(last);
    }
    return last;
    }

    public static void main(String[] args) {
    List<Shape>list1=new ArrayList<>();
    List<Circle>list2=new ArrayList<>();
    list2.add(new Circle());
    list2.add(new Circle());
    Circle circle=MyUtils.copy(list1,list2);
    System.out.println(circle);
    }

    }
    answer:
    com.j1803.Type_wildcards.Circle@4554617c
    上面的方法用到了泛型方法的语法,就是在方法修饰符和返回值类型之间用<>定义泛型形参.

    ========================================================================================================================
    设定泛型形参的上限
      Java泛型不仅允许在使用通配符形参时设定上限,而且可以在定义泛型形参时设定上限,用于表示传给该泛型的形参的实际类型要么是该上限类型,要么就是该上限类型的子类.
    
    
    package com.j1803.Type_wildcards;
    public class AppleDemo <E extends Number>{
    private E info;
    public AppleDemo(E info) {
    this.info = info;
    }
    public E getInfo() {
    return info;
    }
    public static void main(String[] args) {
    AppleDemo<Integer> ai=new AppleDemo<>(23);
    //AppleDemo<Integer> ai1=new AppleDemo<>(45.23);//编译错误
    AppleDemo<Double> di=new AppleDemo<>(23.23);
    //AppleDemo<Double> di1=new AppleDemo<>(45);//编译出错
    //AppleDemo<String> s1=new AppleDemo<String>();//编译出错
    System.out.println(ai.getInfo());
    System.out.println(di.getInfo());
    }
    }


    程序定义了一个AppleDemo泛型类,该AppleDemo类的泛型形参的上限是Number类,这表明使用AppleDemo类时为E形参传入实际类型参数的只能时Number或者Number的子类.
    还有一种更极端的情况下,程序需要为为泛型形参设定多个上限(至多有一个父类上限,可以有多个接口上限),表明该泛型形参必须是其父类的子类(是父类本身也行),并且有多个上限接口.如下代码
    //表明T类型必须是Number类或其子类,并必须实现java.io.serializable接口
    public class AppleDemo<T extends Number & java.io.Seriable>{
    ......
    }


  • 相关阅读:
    Golang gRPC学习(01): gRPC介绍
    MySQL InnoDB存储引擎大观
    SpringBoot学习-图文并茂写Hello World
    Golang的goroutine协程和channel通道
    业务 产品 技术的一点看法
    需求一直做不完,怎么办?
    技术管理:项目开发中的几种风险管理
    go内存管理
    etcd实现分布式锁分析
    强缓存与协商缓存
  • 原文地址:https://www.cnblogs.com/shadow-shine/p/9657796.html
Copyright © 2011-2022 走看看