zoukankan      html  css  js  c++  java
  • Java 泛型学习六 泛型类型系统

    Java 泛型学习一 泛型概念
    Java 泛型学习二 泛型的限制
    Java 泛型学习三 通配符
    Java 泛型学习四 自动擦除
    Java 泛型学习五 泛型擦除带来的不自然
    Java 泛型学习六 泛型类型系统

    在Java语言中,类型系统描述了不同类型之间的转换关系。如果一个类型是另一个类型的子类型,俺们从子类型到父类型的转换是自动进行的,而从父类型到子类型的转换需要再代码中显示进行,这是因为从父类型到子类型的转换可能是不安全的,需要由开发人员显示进行。

    在泛型被引入之前,Java中的父类型和子类型的关系主要通过类继承和接口实现机制来声明。但泛型的引入对Java语言中登录诶性系统产生了比较大的影响。这是因为泛型类型的实例化形式中包含了所使用的实际类型,这些类型之间也可以有父子类型关系。这相当于把类型系统从之前的一维结构扩展为二维结构:泛型类型本身和参数化类型的实际类型。我们来分六种情况看下他们的关系。


    1. 第二维(参数化类型的实际类型)完全相同

    当两个参数化类型的实际类型完全相同时,两个类型的父子类型取决于泛型类型本身的父子关系。如ArrayList<Number>和List<Number>,取决于ArrayList类和List接口之间的父子关系,而ArrayList是List接口的实现,所以ArrayList<Number>是List<Number>的子类型。


    2. 第一维(泛型类型)完全相同

    如果泛型类型相同,在实例化时使用的是不包含通配符的两个不同具体类型,则这两个类型之间不存在任何父子关系,如 ArrayList<Integer> 和 ArrayList<Number>不存在任何父子关系。这一点比较难理解,因为Integer是Number的子类,其实这主要是从安全的角度去考虑的。请看示例代码:

    package net.oseye;
    
    import java.util.ArrayList;
     
    public class FanXing {
    	public static void main(String[] args) {
    		new FanXing().changeList();
    	}
    	
    	public void modify(ArrayList<Number> list){
    		list.add(1.0f); //添加一个Float类型对象
    	}
    	
    	public void changeList(){
    		ArrayList<Integer> list=new ArrayList<Integer>();
    		list.add(3);
    		modify(list); //编译不通过
    	}
    }

    如果ArrayList<Integer> 是 ArrayList<Number>的子类,上面的代码将会抛出运行时异常。


    3. 无界通配符

    无界通配符表示的是全集,包含所有其他的集合,例如List<?>是所有List泛型类的实例化形式父类型,List<String>、List<? extends Number>和List<? super Integer>都是List<?>的子类型。


    4. 有界通配符

    有界通配符的类型系统取决于它的上界和下届。

    • 上界通配符表示的是上界类型及其子类型的集合;
    • 下界通配符和上界通配符的表示的父子关系正好相反;

    例如

    • 上界通配符:"? extends A"和"? extends B"之间的关系取决于类型A和B之间的关系,如果A是B的子类型,那么"? extends A"是"? extends B"的子集,也即是子类型;
    • 下界界通配符:"? super A"和"? super B"之间的关系取决于类型A和B之间的关系,如果B是A的子类型,那么"? super A"是"? super B"的子集,也即是子类型;


    5. 原始类型

    一个泛型类型的所有实例化形式都是其对应的原始类型的子类型,如List<String>和List<? extends Number>都是List的子类型,这种设计目的的为了与不使用泛型的遗留代码进行交互。


    6. 复杂类型

    对于比较复杂的类型判断时,可以根据上面规则从简单的情况开始考虑,比如,在判断ArrayList<Integer>和Collection<? extends Number>之间的关系时,先考虑到ArrayList<Integer>是Collection<Integer>的子类型,而Collection<Integer>是Collection<? extends Number>的子类型,所以ArrayList<Integer>是Collection<? extends Number>的子类型。

    在参数化类型的单个类型中也可以多次使用通配符,如在List<? extends List<? extends Number>>的类型声明中使用了两个上界通配符作为实际的类型。对于这种情况的类型判断比较复杂,基本思路是按照递归的方式一次进行判断,从最内层的类型开始进行判断。比如,对于List<? extends List<Integer>>和List<? extends List<? extends Number>>这两个类型,具体的判断过程是:Integer类型是"? extends Number"的子类型,进而可知List<Integer>是List<? extends Number>的子类型。而List<Integer>和List<? extends Number>作为上届出现,因此List<? extends List<Integer>>是List<? extends List<? extends Number>>的子类型。

  • 相关阅读:
    Android:JNI之Java和C层的相互调用及多线程的回调实现
    高通sdm845_la2.0源码编译及使用QFIL刷机
    git常用指令
    Bouml快速使用指南
    Linux内核数据结构之kfifo详解
    输入系统:进程间双向通信(socketpair+binder)
    Android : 跟我学Binder --- (6) JAVA实现
    【LeetCode】167. Two Sum II
    【LeetCode】1. Two Sum
    【LeetCode】206. Reverse Linked List
  • 原文地址:https://www.cnblogs.com/zhaiqianfeng/p/4618378.html
Copyright © 2011-2022 走看看