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 <T>{
private T x;
}
public class TypeErasureTest {
public static void main(String[] args) {
Point<String> point1 = new Point<>();
Point<Integer> 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<T,E extends Number>{
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<String,Integer> myClass = new MyClass<>();
Class cls = myClass.getClass();
Field[] fields = cls.getDeclaredFields();
for (Field field:fields) {
System.out.println(field.getType());
}
}
}