JDK 泛型之 Type
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 没有指定的话,上边界是 ObjectgetGenericDeclaration返回的是声明这个 Type 所在的类 的 TypegetName返回的是这个 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 有那些方法
}
}
参考:
- 《Type - Java类型》:https://blog.csdn.net/a327369238/article/details/52621043
每天用心记录一点点。内容也许不重要,但习惯很重要!
JDK 泛型之 Type的更多相关文章
- 从fastjson多层泛型嵌套解析,看jdk泛型推断
给你一组json数据结构,你把它解析出来到项目中,你会怎么做? // data1 sample { "code" : "1", "msg" ...
- Java泛型之Type体系
Type是java类型信息体系中的顶级接口,其中Class就是Type的一个直接实现类.此外,Type还有有四个直接子接口:ParameterizedType,TypeVariable,Wildcar ...
- 解决本机安装多版本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 ...
- JDK 泛型
JDK1.5 令我们期待很久,可是当他发布的时候却更换版本号为5.0.这说明Java已经有大幅度的变化.本文将讲解JDK5.0支持的新功能-----Java的泛型. 1.Java泛型 其实Java的泛 ...
- Spring杂谈 | 你真的了解泛型吗?从java的Type到Spring的ResolvableType
关于泛型的基本知识在本文中不会过多提及,本文主要解决的是如何处理泛型,以及java中Type接口下对泛型的一套处理机制,进而分析Spring中的ResolvableType. 文章目录 Type 简介 ...
- java 泛型基础问题汇总
泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型接口.泛型方法. Java语言引 ...
- Mybatis框架基础支持层——反射工具箱之泛型解析工具TypeParameterResolver(4)
简介:TypeParameterResolver是一个工具类,提供一系列的静态方法,去解析类中的字段.方法返回值.方法参数的类型. 在正式介绍TypeParameterResolver之前,先介绍一个 ...
- 重学Java泛型
一丶从字节码层面看范型擦除 public class Type1<T> { private T t; } 使用jclasslib插件查看其字节码: 可以看到 t属性的类型是List< ...
- Java 8 新特性之泛型的类型推导
1. 泛型究竟是什么? 在讨论类型推导(type inference)之前,必须回顾一下什么是泛型(Generic).泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据 ...
随机推荐
- 并发工具类(二)同步屏障CyclicBarrier
前言 JDK中为了处理线程之间的同步问题,除了提供锁机制之外,还提供了几个非常有用的并发工具类:CountDownLatch.CyclicBarrier.Semphore.Exchanger.Ph ...
- Sass、Less编译器koala及koala不支持中文字体的解决方法
一款很好用的Sass编译器,还可以编译Less.coffeescript等 去官网下载适合自己电脑的版本 http://koala-app.com/index-zh.html 打开后拖动或者打开项目目 ...
- django中使用Ajax
内容: 1.Ajax原理与基本使用 2.Ajax发送get请求 3.Ajax发送post请求 4.Ajax上传文件 5.Ajax设置csrf_token 6.django序列化 参考:https:// ...
- catpcha
生成随机验证码: # -*- coding: utf-8 -*- # @Author: huangyong # @Date: 2016-10-29 22:18:38 # @Last Modified ...
- python中函数的返回值
函数返回值(一) <1>“返回值”介绍 现实生活中的场景: 我给儿子10块钱,让他给我买包烟.这个例子中,10块钱是我给儿子的,就相当于调用函数时传递到参数,让儿子买烟这个事情最终的目标是 ...
- Mysql 开启Federated引擎以及使用
FEDERATED是其中一个专门针对远程数据库的实现.但通过FEDERATED引擎创建的表只是在本地有表定义文件,数据文件则存在于远程数据库中通过这个引擎可以实现类似Oracle 下DBLINK的远程 ...
- jdk配置(备份)
#####set java environment #export JAVA_HOME=/usr/java/jdk1..0_172 #export JRE_HOME=${JAVA_HOME}/jre ...
- Mybatis like模糊查询的写法
转自:http://blog.51cto.com/lavasoft/1386870 Mybatis like查询官方文档没有明确的例子可循,网上搜索了很多,都不正确. Mybatis 3.2.6经过尝 ...
- session失效刷新后登录页面嵌入在iframe中的前台解决办法
在前台登录页面中加入JS代码,判断登录页面是否在iframe中,在iframe中就跳转出去 例: //判断是否在iframe中,在里面就跳出去 if (top.location.href != loc ...
- bootstrap左侧边栏
之前都是想直接把导航栏放左边,但是会占一整行 网上找了好久,看到用bootstrap响应式布局,可以比较简单实现 经典的,可以参考:http://demo.qianduanblog.com/3150/ ...