Java基础——泛型之通配符与类型擦除

Java基础——泛型之通配符与类型擦除

一、通配符?

  Java泛型的通配符有三种形式,但究其根本只有"?“这一种形式,其他两种形式都是由”?"衍生出来的。

  1、?:可以接收任意类型——只能作用于方法上,不能修改值

    表示参数可以接收任意类型的泛型类,只能取得类中数据,不能修改数据,因为类型不确定,无法设置确定类型。(只知道是个泛型,连具体是什么类都不知道,肯定不能修改set值)

  2、 ? extends 类:设置/取得泛型上限——可用在类或方法上,不能修改值

    用在类上:T extends 类:T必须为类或者类的子类(不能用?)
    用在方法上:? extends 类:只能接收类或者其子类的泛型类,只能取得类中属性值,不能修改值(会发生父类到子类的向下转型,需要强转,由于具体子类不确定,因此无法转型)
	? extends Number:表示泛型必须是Number及其子类

  3、 ? super 类:取得泛型下限——只能用于方法中,可以修改值

    除了可以取值,也可以设置属性值(子类到父类是自动的向上转型)
	? super String:表示此方法只能取得String以及其父类(Object)	

  这个?代表的就是某个泛型类,若是2/3的情况,则看?代表的那个 类和后面类的关系,若是继承了后面的类,则根据后面的类(父类)并不能确定该子类到底是哪一个类(向下转型),而若是后面的类的父类,则可以设置后面的类(修改值),因为会发生向上转型(自动的)

  4、通配符的关系

    ①只有extends才能用在泛型类上(还是T)
    ②只有super才能设置值

二、类型擦除(语法糖)

  1、先说一下语法糖的概念

    语法糖(为了方便开发):仅存在与源码阶段,编译后就消失不见。Java中典型的语法糖有泛型,自动拆装箱,String的"+"。

  2、类型擦除: 泛型信息仅存在于代码的编译阶段,编译以后就没了,进入JVM之前,与泛型相关的信息会被擦除掉(泛型类与普通类在Java虚拟机(JVM)内没有任何区别

package com.xiaoaxiao.test.GenericTest;

/**
 * Created by xiaoaxiao on 2019/7/10
 * Description: 类型擦除测试
 */

class Point {
    private T x;
}

public class TypeErasureTest {
    public static void main(String[] args) {
        Point point1 = new Point<>();
        Point point2 = new Point<>();
        // point1和point2的class相同说明:泛型被类型擦除了,实际进入JVM的都是普通类
        System.out.println(point1.getClass()==point2.getClass());
    }
}

  3、类型擦除的具体实现: 泛型类进入JVM之前会进行类型擦除,之前泛型类的类型参数若没有指定上限,会被擦除为Object类型若指定上限,则类型参数被替换为相应的类型上限

package com.xiaoaxiao.test.GenericTest;

import java.lang.reflect.Field;

/**
 * Created by xiaoaxiao on 2019/7/10
 * Description: 泛型类的类型参数若没有指定上限,会被擦除为Object类型。
 *              如果指定上限,则类型参数被替换为相应的类型上限。
 */

class MyClass{
    private T message;
    private E text;

    public T getMessage() {
        return message;
    }

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

    public E getText() {
        return text;
    }

    public void setText(E text) {
        this.text = text;
    }
}

public class TypeErasurePlus {

    public static void main(String[] args) {
        MyClass myClass = new MyClass<>();
        Class cls = myClass.getClass();
        Field[] fields = cls.getDeclaredFields();
        for (Field field:fields) {
            System.out.println(field.getType());
        }
    }
}

你可能感兴趣的:(JavaSE基础学习,通配符,泛型,类型擦除)