今天我们不讲泛型的来龙去脉,讲讲泛型到底有哪些类别,也就是Type这个接口到底有多少不同的实现(jdk中)
大家可能会疑惑,泛型还能有多种不同的类型?
这不是我前段时间写了一个库【Java】简单优雅的加载外部 jar 中的 Class|插件化
在这个库中我需要实现一个功能:通过泛型来推导数据类型来加载对应的插件内容
于是我就对我们平时常用的泛型做了一些研究
如果大家之前有去了解过相关的内容,就会知道Type接口会有一些不同的实现(jdk中)
- Class
- TypeVariable
- ParameterizedType
- WildcardType
- GenericArrayType
那么今天我们就来看看这些类型都对应了什么写法的泛型
Class首先Class我们接触的比较多,虽然实现了Type接口,但不是泛型,就是普通的类的类型,并不具有泛型的一些参数属性
TypeVariable可变类型,可以得到最原始的类型信息
如我们常用的ArrayList
我们可以通过getTypeParameters来获得他的泛型信息
ArrayList.class.getTypeParameters();
但是我们只能拿到E,拿不到具体的类型,毕竟实例化之后任意的类型都有可能
那么有没有能拿到具体类型的泛型呢,我们继续往下看
ParameterizedType参数化类型,可以获得< >中定义的具体类型
假设我们继承ArrayList并指定泛型为String
public class StringArrayList extends ArrayList{ }
这种情况下,我们就可以使用getGenericSuperclass来获得泛型信息
StringArrayList.class.getGenericSuperclass();
调用上面的方法我们就能得到一个ParameterizedType
通过ParameterizedType#getRawType()就可以获得ArrayList.class
通过ParameterizedType#getActualTypeArguments()就可以获得String.class
ParameterizedType type = (ParameterizedType) StringArrayList.class.getGenericSuperclass(); Type rawType = type.getRawType(); System.out.println(rawType); //输出 class java.util.ArrayList Type actualTypeArgument = type.getActualTypeArguments()[0]; System.out.println(actualTypeArgument); //输出 class java.lang.StringWildcardType
通配符类型,可以获得泛型的类型界限
主要通过? extends或? super约束
举个例子
public class ClassArrayList extends ArrayList> { }
其中? extends Serializable就是WildcardType
这里需要注意的是不带< >
通过WildcardType#getUpperBounds()就可以获得Serializable.class
ParameterizedType type = (ParameterizedType) ClassArrayList.class.getGenericSuperclass(); Type rawType = type.getRawType(); System.out.println(rawType); //输出 class java.util.ArrayList ParameterizedType actualTypeArgument = (ParameterizedType) type.getActualTypeArguments()[0]; System.out.println(actualTypeArgument); //输出 java.lang.Class extends java.io.Serializable> Type argumentRawType = actualTypeArgument.getRawType(); System.out.println(argumentRawType); //输出 class java.lang.Class WildcardType argumentActualTypeArgument = (WildcardType) actualTypeArgument.getActualTypeArguments()[0]; System.out.println(argumentActualTypeArgument); //输出 ? extends java.io.Serializable Type upperBound = argumentActualTypeArgument.getUpperBounds()[0]; System.out.println(upperBound); //输出 interface java.io.SerializableGenericArrayType
泛型数组类型,表示泛型类型的数组类型
修改一下上面的例子
public class ClassesArrayList extends ArrayList[]> { }
实际上就是在原本的泛型类型外又包了一层
ParameterizedType type = (ParameterizedType) ClassesArrayList.class.getGenericSuperclass(); Type rawType = type.getRawType(); System.out.println(rawType); //输出 class java.util.ArrayList GenericArrayType actualTypeArgument = (GenericArrayType) type.getActualTypeArguments()[0]; System.out.println(actualTypeArgument); //输出 java.lang.Class extends java.io.Serializable>[] ParameterizedType genericComponentType = (ParameterizedType) actualTypeArgument.getGenericComponentType(); System.out.println(genericComponentType); //输出 java.lang.Class extends java.io.Serializable> Type argumentRawType = genericComponentType.getRawType(); System.out.println(argumentRawType); //输出 class java.lang.Class WildcardType argumentActualTypeArgument = (WildcardType) genericComponentType.getActualTypeArguments()[0]; System.out.println(argumentActualTypeArgument); //输出 ? extends java.io.Serializable Type upperBound = argumentActualTypeArgument.getUpperBounds()[0]; System.out.println(upperBound); //输出 interface java.io.Serializable没见过的泛型写法
接下来再说一个我在查资料时见到的一种泛型写法
public class Custom{ }
不知道大家之前有没有遇到过这样的写法
然后我就研究了一下,发现这其实就是一个AND条件
上面的接口表示,这个泛型必须要实现Serializable和Cloneable,两个都要满足
所以比如ArrayList就是可以的:Custom
而且泛型中的条件可以有多个,但是最多只能有一个类,其他必须为接口
可以猜想是java只能继承一个父类但是可以实现多个接口的原因
那么今天的内容就是这样啦
其他的文章【Java】简单优雅的加载外部 jar 中的 Class|插件化
【Spring Boot】一个注解实现下载接口
【拿来吧你】JDK动态代理
【Java】异步回调转为同步返回



