JDK 泛型之 Type

一、Type 接口

JDK 1.5 引入 Type,主要是为了泛型,没有泛型的之前,只有所谓的原始类型。此时,所有的原始类型都通过字节码文件类 Class 类进行抽象。Class 类的一个具体对象就代表一个指定的原始类型。

泛型出现后扩充了数据类型,从只有原始类型扩充了参数化类型、类型变量类型、泛型数组类型。Type 的子接口有:ParameterizedType、TypeVariable、GenericArrayType、WildcardType,实现类有 Class。

Type 体系中类型的包括:原始类型(Class)、基本类型(Class)、类型变量(TypeVariable)、参数化类型(ParameterizedType)、数组类型(GenericArrayType)。

  • 原始类型(Class):不仅仅包含我们平常所指的类,还包括枚举、数组、注解等;
  • 基本类型(Class):也就是我们所说的 java 的基本类型,即 int, float, double 等;
  • 类型变量(TypeVariable):各种类型变量的公共父接口,就是泛型里面的类似 T、E,即泛型变量;
  • 参数化类型(ParameterizedType):就是我们平常所用到的泛型 List、Map;
  • 数组类型(GenericArrayType):并不是我们工作中所使用的数组 String[] 、byte[],而是泛型数组 T[] ;
// 1. 原始类型(Class)
Set set;
List aList;
String[] arr; // 2. 参数化类型(ParameterizedType)
Map<String, Person> map;
Set<String> set;
Class<?> clazz;
List<String> list; // 3. 类型变量(TypeVariable)
T t; // 4. 数组类型(GenericArrayType)
Class<?>[] clazz;
Map<String, Person>[] clazz;

一、参数化类型(ParameterizedType)

ParameterizedType,参数化类型,形如:Object<T, K>,即常说的泛型,是 Type 的子接口。

public interface ParameterizedType extends Type {
// 1. 获得<>中实际类型
Type[] getActualTypeArguments(); // 2. 获得 <> 前面实际类型
Type getRawType(); // 3. 如果这个类型是某个类型所属,获得这个所有者类型,否则返回 null
Type getOwnerType();
}

(1) getActualTypeArguments

返回这个 Type 类型的参数的实际类型数组,即 <> 里的类型参数的类型,因为可能有多个类型参数,例如 Map<K, V>,所以返回的是一个 Type[] 数组。

【注意】无论 <> 中有几层 <> 嵌套,这个方法仅仅脱去最外层的 <>,之后剩下的内容就作为这个方法的返回值,所以其返回值类型不一定。

public class ParameterizedTypeTest<T> {
List<Set> a1; // 返回 Set,Class 类型
List<Set<String>> a2; // 返回 Set<String>,ParameterizedType 类型
List<T> a3; // 返回 T,TypeVariable 类型
List<? extends Set> a4; // 返回 WildcardType 类型
List<Set<String>[]> a5; // 返回 GenericArrayType 类型 @Test
public void test1() throws Exception {
Method method = getClass().getMethod("test", List.class);
Type[] types = method.getGenericParameterTypes();
ParameterizedType pType = (ParameterizedType) types[0];
Type[] type = pType.getActualTypeArguments();
// sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl
System.out.println(type[0].getClass().getName());
} public void test(List<ArrayList<String>[]> a) {
}
}

(2) getRawType

返回的是当前这个 ParameterizedType 的类型,即最外层 <> 前面那个类型,如 Map<K ,V> 的 Map

Map.Entry<String, Integer> me;
@Test
public void rawTypeTest() throws Exception {
Field field = getClass().getDeclaredField("me");
ParameterizedType type = (ParameterizedType) field.getGenericType();
// java.util.Map$Entry
System.out.println(type.getRawType());
}

(3) getOwnerType

返回的是这个 ParameterizedType 所在的类的 Type。

Map.Entry<String, Integer> me;
@Test
public void ownerTypeTest() throws Exception {
Field field = getClass().getDeclaredField("me");
ParameterizedType type = (ParameterizedType) field.getGenericType();
// java.util.Map
System.out.println(type.getOwnerType());
}

三、TypeVariable(类型变量)

TypeVariable 描述所谓范型变量,也就是 或者

public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
// 变量上边界数组,没有指定的话是 Object
Type[] getBounds(); // 获取变量被定义在什么 GenericDeclaration 上
D getGenericDeclaration(); // 获取变量名字
String getName(); // jdk 1.8
AnnotatedType[] getAnnotatedBounds();
}
  • getBounds 得到上边界的 Type 数组,如 K 的上边界数组是 InputStream 和 Serializable。V 没有指定的话,上边界是 Object
  • getGenericDeclaration 返回的是声明这个 Type 所在的类 的 Type
  • getName 返回的是这个 type variable 的名称

(1) getBounds

获取泛型变量的上边界的 Type 数组,如果没有指定则是 Object。

@Test
public void test() {
// 1. 获取类上声明的泛型变量 getTypeParameters
TypeVariable<Class<TypeVariable>> typeVariable = TypeVariable.class.getTypeParameters()[0];
// 2. 获取泛型变量的上边界 java.lang.reflect.GenericDeclaration
System.out.println(Arrays.toString(typeVariable.getBounds()));
}

(2) getGenericDeclaration

GenericDeclaration 该接口用来定义哪些对象上是可以声明范型变量,目前实现 GenericDeclaration 接口的类包括 Class、Method、Constructor,也就是说只能在这几种对象上进行范型变量的声明(定义)。

public class TypeVariableTest<E> {
@Test
public void getGenericDeclarationTest() {
// 1. 类上声明泛型
TypeVariable<Class<TypeVariableTest>> classType = TypeVariableTest.class.getTypeParameters()[0];
Class<TypeVariableTest> clazzDeclaration = classType.getGenericDeclaration();
// class com.github.binarylei.spring01.day0728.test.TypeVariableTest
System.out.println(clazzDeclaration); // 2. 方法上声明泛型
Method[] methods = TypeVariableTest.class.getMethods();
Method method = Arrays.stream(methods)
.filter(m -> m.getName().equals("test"))
.collect(Collectors.toList())
.get(0);
TypeVariable methodType = (TypeVariable) method.getGenericParameterTypes()[0];
GenericDeclaration methodDeclaration = methodType.getGenericDeclaration();
// public void com.github.binarylei.TypeVariableTest.test(java.lang.Object)
System.out.println(methodDeclaration); // 3. 构造器上声明泛型
} public <T> void test(T t) {
}
}

四、GenericArrayType(数组类型)

范型数组,组成数组的元素中有范型则实现了该接口;它的组成元素是 ParameterizedType 或 TypeVariable 类型

public interface GenericArrayType extends Type {
// 获得这个数组元素类型,即获得:A<T>(A<T>[])或T(T[])
Type getGenericComponentType();
}

下面我们一起来看一下例子:

classA<K>[][] key;

Type type = Main.class.getDeclaredField("key").getGenericType();
// com.github.binarylei..classA<K>[]
System.out.println(((GenericArrayType)type).getGenericComponentType());

五、WildcardType(通配符的类型)

WildcardType,通配符表达式,Type 子接口,但是在 Java 中并没有 WildcardType 类型。extends 用来指定上边界,没有指定的话上边界默认是 Object,super 用来指定下边界,没有指定的话为 null。

几个主要方法介绍:

public interface WildcardType extends Type {
Type[] getUpperBounds();
Type[] getLowerBounds();
}
  • getLowerBounds 得到上边界 Type 的数组

  • getUpperBounds 得到下边界 Type 的数组

下面一起来看一下例子:

public class WildcardTypeTest {

    // 指定上界 Number,下边界默认为 []
private List<? extends Number> a;
// 指定下界 String,上边界默认是 Object
private List<? super String> b;
// 上界和下界都不指定,上边界默认是 Object,下边界默认为 []
private Class<?> clazz; // 没有通配符,不是 WildcardType
private List<String> c; @Test
public void test() throws Exception {
Field[] fields = WildcardTypeTest.class.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
Type type = field.getGenericType();
String nameString = field.getName();
//1. 先拿到范型类型
if (!(type instanceof ParameterizedType)) {
continue;
} //2. 再从范型里拿到通配符类型
ParameterizedType parameterizedType = (ParameterizedType) type;
type = parameterizedType.getActualTypeArguments()[0];
if (!(type instanceof WildcardType)) {
continue;
} System.out.println("-------------" + nameString + "--------------");
WildcardType wildcardType = (WildcardType) type;
Type[] lowerTypes = wildcardType.getLowerBounds();
if (lowerTypes != null) {
System.out.println("下边界:" + Arrays.toString(lowerTypes));
}
Type[] upTypes = wildcardType.getUpperBounds();
if (upTypes != null) {
System.out.println("上边界:" + Arrays.toString(upTypes));
}
}
}
}

六、GenericDeclaration

GenericDeclaration 该接口用来定义哪些对象上是可以声明范型变量,目前实现 GenericDeclaration 接口的类包括 Class、Method、Constructor,也就是说只能在这几种对象上进行范型变量的声明(定义)。

GenericDeclaration 的接口方法 getTypeParameters 用来逐个获取该 GenericDeclaration 的范型变量声明。

public interface GenericDeclaration extends AnnotatedElement {
// 用来获取该GenericDeclaration的范型变量声明
public TypeVariable<?>[] getTypeParameters();
}

(1) 泛型的声明

//1. 在类(Class)上声明
class A<T> { T a; } // 2. 在方法上声明
// 类型变量声明不是在参数里边,而且必须在返回值之前,static 等修饰后
public <E> void test(E e) {} // 3. 在构造器上声明
public <K> A(K k) {}

【注意】类型变量声明(定义)的时候不能有下限(既不能有 super),否则编译报错。为什么?T extends classA 表示泛型有上限 classA,当然可以,因为这样,每一个传进来的类型必定是 classA(具有 classA 的一切属性和方法),但若是 T super classA,传进来的类型不一定具有 classA 的属性和方法,当然就不适用于泛型,说的具体点:

class A<T super classA>{
T t;
public void test(){
// t 的子类是 classA,我们还是不知道 t 到底是什么类型,不知道 t 有那些方法
}
}

参考:

  1. 《Type - Java类型》:https://blog.csdn.net/a327369238/article/details/52621043

每天用心记录一点点。内容也许不重要,但习惯很重要!

JDK 泛型之 Type的更多相关文章

  1. 从fastjson多层泛型嵌套解析,看jdk泛型推断

    给你一组json数据结构,你把它解析出来到项目中,你会怎么做? // data1 sample { "code" : "1", "msg" ...

  2. Java泛型之Type体系

    Type是java类型信息体系中的顶级接口,其中Class就是Type的一个直接实现类.此外,Type还有有四个直接子接口:ParameterizedType,TypeVariable,Wildcar ...

  3. 解决本机安装多版本jdk导致The type java.lang.Object cannot be resolved It is indirectly referenced ...

    本机开始安装了jdk1.6,然后安装了jdk1.8 当在调自动化的时候,发现传入函数传参String类型,报错The type java.lang.Object cannot be resolved ...

  4. JDK 泛型

    JDK1.5 令我们期待很久,可是当他发布的时候却更换版本号为5.0.这说明Java已经有大幅度的变化.本文将讲解JDK5.0支持的新功能-----Java的泛型. 1.Java泛型 其实Java的泛 ...

  5. Spring杂谈 | 你真的了解泛型吗?从java的Type到Spring的ResolvableType

    关于泛型的基本知识在本文中不会过多提及,本文主要解决的是如何处理泛型,以及java中Type接口下对泛型的一套处理机制,进而分析Spring中的ResolvableType. 文章目录 Type 简介 ...

  6. java 泛型基础问题汇总

    泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型接口.泛型方法. Java语言引 ...

  7. Mybatis框架基础支持层——反射工具箱之泛型解析工具TypeParameterResolver(4)

    简介:TypeParameterResolver是一个工具类,提供一系列的静态方法,去解析类中的字段.方法返回值.方法参数的类型. 在正式介绍TypeParameterResolver之前,先介绍一个 ...

  8. 重学Java泛型

    一丶从字节码层面看范型擦除 public class Type1<T> { private T t; } 使用jclasslib插件查看其字节码: 可以看到 t属性的类型是List< ...

  9. Java 8 新特性之泛型的类型推导

    1. 泛型究竟是什么? 在讨论类型推导(type inference)之前,必须回顾一下什么是泛型(Generic).泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据 ...

随机推荐

  1. CSS3基础

    内容: 1.圆角 border-radius 2.阴影 text-shadow.box-shadow 3.渐变 linear.radial 4.rgba rgb+alpha opacity 5.tra ...

  2. node.js入门基础

    内容: 1.node.js介绍 2.node.js内置常用模块 3.node.js数据交互 一.node.js介绍 (1)node.js特点 与其他语言相比,有以下优点: 对象.语法和JavaScri ...

  3. Bogart gGrid.vb

    Namespace BogartMis.Cls Public Class gGrid '設定表格控的列標題的別名 '說明:strItem字符串的格式為"01,02,03,04,05" ...

  4. vi规范

    pep8规范 # vi规范## , 后空一格# 函数和其他代码空两行

  5. 40. Linux下7-zip解压到当前目录的命令

    7z x test.zip 解压到当前目录下,但保留原来的目录结构 7z e test.zip 解压到当前目录下,不保留原来的目录结构

  6. HTML 标签元素的 align 属性

    align 属性规定段落中文本的对齐方式. 有 left  right center  justify 这些参数 left  right center  就是左对齐 右对齐 中间对齐 justify  ...

  7. 使用seaborn制图(柱状图)

    import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns # 设置风格, ...

  8. 多媒体基础知识之PCM数据

    1.什么是PCM音频数据 PCM(Pulse Code Modulation)也被称为脉冲编码调制.PCM音频数据是未经压缩的音频采样数据裸流,它是由模拟信号经过采样.量化.编码转换成的标准的数字音频 ...

  9. 9 并发编程-(线程)-守护线程&互斥锁

    一 .守护线程 无论是进程还是线程,都遵循:守护xxx会等待主xxx运行完毕后被销毁 需要强调的是:运行完毕并非终止运行 1.对主进程来说,运行完毕指的是主进程代码运行完毕 2.对主线程来说,运行完毕 ...

  10. MIME(Multipurpose Internet Mail Extensions-多用途互联网邮件扩展)

    MIME MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型.是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时 ...