范型的历史机源
Java 5之前 Java的设计者没有考虑范型引入jvm,后果是 Java 已经发展了很多年,形成历史技术债务。
Java 语言以及 JVM 推出后,由于它的跨平台性,通用的字节码,虚拟机,它能够运行在 Web 上,GC 等特性,迅速在全球流行开来,同时也吸引了很多学界和产业界人士的关注,其中就包括当时在德国卡尔斯鲁厄大学任教的 Martin Odersky(也是 scala 之父)。他和其在英国格拉斯哥大学的研究伙伴 Phil Wadler 于 1996 年共同开发了 Pizza 语言,该语言运行在 JVM 上,支持泛型,高阶函数和模式匹配等函数式编程功能。由于 Pizza 的目标是填补 Java 欠缺的功能,因此受到 Sun 公司的关注,于是 Sun 的工程师和 Martin Odersky、Phil Wadler 合作,借鉴 Pizza 的泛型实现开发了支持泛型的 Java 扩展版本:GJ,即 Generic Java。
GJ 所支持的泛型支持同类转化(homogeneous,指编译器把泛型中的类型参数都翻译为相同的 Object),异类转化(heterogeneous,指编译器把不同类型参数的泛型翻译为不同参数化的类),支持值类型范型。但由于要兼容不支持泛型的旧版本,Java 最终采用了类型擦除(type erasure)这一同类转化的方案,并引入了通配符,这样就构成了 2004 年发布的 Java 5 的泛型的基础
Java 的泛型仍在进化,JEP218 即 Project Valhalla 旨在支持值类型范型,并引入泛型可 reifiable 机制,即在运行时可读取类型参数的类型信息,但发布时间尚未确定。
泛型的设计理念
通过类型擦除实现 Java 泛型。为了兼容旧版本,Java 的设计者认为对于 JVM 来讲不支持泛型的代码应当和支持泛型的代码是透明的,两者没有区别;同时也不想为泛型开发一套新的平行的 API,最终采用了类型擦除的方案。所有的泛型类型参数都在编译期间转为 Object 对象,而基本类型 int、long、double 等不是对象类型,所以 Java 泛型暂不支持基本类型。
保证类型安全,避免运行时 ClassCastException。泛型有助于在编译期检查代码的类型安全,采用范型的代码要能够保证运行期不会出现 ClassCastException。保证类型安全这一点对于 OOP 语言至关重要,它通过编译期严格的类型检查,有效避免运行时的错误。
//无论范型是什么类型,编译后会进行类型擦除,变成 object
List<Object> list=new ArrayList<Object>();
/*
* 编译器强制要求表达式俩边是统一的类型,目的是保证不发生 ClassCastException 异常
* 如果编译器支持以下的代码,第一行代码会引入 ClassCastException 异常
* 第二行代码会进行强制转换,没有必要
* 第二行的代码也没有继承关系,不能说 String 继承 Object 就是集合也存在继承关系
* 因为 new ArrayList<String> 其实是 ArrayList<Object>()
*/
❌ List<String> strList=new ArrayList<Object>();
❌ List<Object> objList=new ArrayList<String>();
验证类型擦除,在 jvm 里 输出一样的结果,说明引入范型号只是编译器层面方便程序员写出规范代码 到jvm 里都是 Object,保证了 java5 之前的代码,能够继续使用,在 jvm 里根本没有范型这个概念
var bar= new ArrayList<String>().getClass();
var foo= new ArrayList<Integer>().getClass();
var zar= new ArrayList<Object>().getClass();
var zoo= new ArrayList().getClass();
System.out.println(bar.getName()); //java.util.ArrayList
System.out.println(foo.getName()); //java.util.ArrayList
System.out.println(zar.getName()); //java.util.ArrayList
System.out.println(zoo.getName()); //java.util.ArrayList
❌异常类不能被泛化,如下代码是不允许的,因为这样没有意义
class MyException<T> extends Exception{
}
try {}catch (MyException<String> e){}
catch (MyException<Integer> e){}
//编译后变成这样,那到底是进入第一个 catch 还是第二个 catch 合适
//会引起混乱,所以编译器不允许 异常类泛化
try {}catch (MyException<Object> e){}
catch (MyException<Object> e){}
✅ 但可以声明类型变量为异常类
class ThrowException<E extends Exception>{
void errMethod(E e) throws Exception {throw e;}
}
❌方法重载不成立,类型擦除后都是 ArrayList<Object>
//'method(ArrayList<String>)' 与 'method(ArrayList<Date>)' 冲突;两个方法具有相同的擦除
public class Test {
❌ public void method(ArrayList<String> list) {
System.out.println("Arraylist<String> list");
}
❌ public void method(ArrayList<Date> list) {
System.out.println("Arraylist<Date> list");
}
}
基本的使用
一般普遍常用的泛型名字:
- E - Element 容器类元素
- K — Key map 中的 key
- N - Number
- T - Type
- V - Value
- S,U,V etc. - 2nd, 3rd, 4th types
泛型不适合父子继承关系,会破环继承关系
public class A {
@Data
public static class Parent<T> { private T t;}
public static class Child extends Parent<Date>{
@Override
public Date getT() {return super.getT();}
@Override
public void setT(Date date) {super.setT(date);}
}
public static void main(String[] args) {
//子类的泛型参数是 Date
Child child=new Child();
child.setT(new Date());
var bar= child.getT();
//这里的父类,泛型参数是 Object ,因为默认不指定就是 object
Parent parent=child;
//虽然父类指向了子类,泛型破环了父子类的继承关系,此时在编译器看来setT() 是用的父类的方法约束,
//但是jvm 哪里执行的却是子类的方法
//运行时❌抛出错误 class java.lang.String cannot be cast to class java.util.Date
//此错误在编译器不会发现
parent.setT("");
var foo=parent.getT();
}
}
自定义比较大小
public class Bar {
public static <T extends Comparable<T>> T max(T t1,T t2){
return (t1.compareTo(t2)>0) ?t1:t2;
}
public static void main(String[] args) {
System.out.println(max(10,5));
}
}
范型的桥接方法
继承关系的泛型类
public abstract class Parent<T> {
abstract T get(T t);
}
//
public class Sun extends Parent<String> {
@Override
String get(String s) {
return "";
}
}
如果编译后是这样的代码,继承关系就破环了,语法上就通不过
public abstract class Parent {
abstract Object get(Object t);
}
//
public class Sun extends Parent<String> {
@Override
String get(String s) {
return "";
}
}
利用编译器桥接生成的代码可以保留继承关系,同时有能保留原来的方法 get(String s)
//类型擦除
public abstract class Parent {
abstract Object get(Object t);
}
public class Sun extends Parent<String> {
/*
Parent 类型会被擦除为 Object
需要保留原来的 Parent 的原来的方法
👍👍👍编译器添加的桥接方法
*/
public Object get(Object t){
return get((String) t);
}
//但是这里的方法参数还要保留到运行时
@Override
public String get(String s) {
return s;
}
}
泛型的上下边界和通配符
上下边界 extends
通过 extends 限制泛型参数边界,如下显示,不能有多继承类,但是允许有多个接口,继承的类必须位于开头位置
<T extends B1 & B2 & B3>
class Order{ }
interface Cargo{ }
class Far extends Order implements Cargo,Serializable{
}
public class A {
//通过 extends 限制泛型参数只能是 Order & 实现 Cargo & Serializable 的类或其子类
public static <T extends Order & Cargo & Serializable> T getFirst(List<T> list){
var ret =list.get(0);
return ret;
}
public static void main(String[] args) {
var list =new ArrayList<Far>();
getFirst(list);
}
}
通配符 ——协变(Covariance)和逆变(Contravariance)
泛型是与 OOP 强关联的技术,而协变和逆变也是关于继承关系的理论,因此两者在很多方面是贯通的。 里氏替换原则,它指出如果一个类型 S 是类型 T 的子类,那么程序中任何 T 的对象出现的地方都可以用 S 的对象来替换,因为 S 的对象包含了 T 的对象的所有信息。这里的类型不一定就是类,也可以是接口、函数或方法 。里氏替换原则是协变和逆变的基础
首先,协变和逆变这两个概念在数学和物理界已经应用很广泛,它强调的是当变量发生变化时,所研究对象变化的方向与该变量变化的方向是否一致,如果一致就是协变,否则就是逆变。 y=f(x) 如果 x 变大 y 也变大,就是协变,否者就是逆变,就是这么简单
Java泛型中的通配符机制的目的是:让一个持有特定类型(比如A类型)的集合能够强制转换为持有A的子类或父类型的集合,通配符是配合泛型集合使用的
泛型通配符可以解决这个问题。泛型通配符主要针对以下两种需求:
- 从一个泛型集合里面读取元素 上界通配符,作为函数的参数
- 往一个泛型集合里面插入元素 下界通配符,作为函数的返回值 这里有三种方式定义一个使用泛型通配符的集合(变量)。如下:
<?>
<? extends A> 指定上界
<? super A> 指定下界
泛型的通配符 ?,有的时候也称为无边界通配符,就是传递啥都可以
为什么要有通配符,因为集合类型之间不存在继承关系,通过通配符来适配这种关系
✅ Object obj1="hello";
✅ Object obj2=1;
//按照 上面的例子如下例子看似可以通过编译,实际却不能通过编译
❌ArrayList<Object> strList=new ArrayList<String>();
❌ArrayList<Object> intList=new ArrayList<Integer>();
如果泛型的集合允许把子类集合赋值给父类集合
class Parent{
}
class Child1 extends Parent {
}
class Child2 extends Parent {
}
class GenericsType {
public static void main(String[] args) {
var list = new ArrayList<Child1>();
list.add(new Child1());
❓ List<Parent> parentList=list;
//就算上面的编译能通过
//这里 parentList 添加 Child1 及 Parent 的后果是类型转换错误
//因为 Child1 不能传入不是自己及其子类的类型对象
parentList.add(new Child2());
parentList.add(new Parent());
}
}
如下例子printList 方法的参数是 List
class GenericsType {
public static void main(String[] args) {
List<String> list = new ArrayList<>(){
{add("hello");}
};
List<Integer> list2 = new ArrayList<>(){
{add(1);}
};
❌ GenericsType.printList(list);
❌ GenericsType.printList(list2);
}
public static void printList(❌ List<Object> list) {
list.forEach(p->{
System.out.print(p + " ");
});
}
}
代码改成如下形式编译通过 因为你不知道集合是哪种类型,所以你只能够对集合进行读操作。并且你只能把读取到的元素当成 Object 实例来对待。 下面是一个例子:
public static void printList(✅ List<?> list) {
//不能修改增加元素,但是可以删除元素
list.forEach(p->{
// p 是啥类型这里根本不知道,只能是当作 object 对待,因为不知道集合元素是什么类型
// 不能给集合添加类型
System.out.print(p + " ");
});
}
? 通配符的限界
演示类
interface superParentInterface {
}
interface ParentInterface extends superParentInterface {
}
interface UncleInterface extends superParentInterface {
}
class superParent1 implements superParentInterface{
}
class Parent1 implements ParentInterface {
}
class Uncle1 implements UncleInterface {
}
class superParent {
}
class Parent extends superParent implements ParentInterface {
}
class Uncle extends superParent {
}
class Child1 extends Parent {
}
class Child2 extends Parent {
}
class Son1 extends Child1 {
}
class Son2 extends Child1 {
}
上界通配符
上界通配符,用来指定范围的上边界,不限制下边界。堵住往上的路,来缩小类型参数的类型范围,传入的类型只能是Parent(上边界) 及其子类 Child1 或 Child2,它的语法形式为:<? extends Parent>
class GenericsType {
public static void main(String[] args) {
{
var list1 = new ArrayList<Child1>();
doSome(list1);
var list2 = new ArrayList<Child2>();
doSome(list2);
}
{
var list1 = new ArrayList<Son1>();
doSome(list1);
var list2 = new ArrayList<Son2>();
doSome(list2);
}
{
var list1 = new ArrayList<Parent>();
doSome(list1);
var list2 = new ArrayList<ParentInterface>();
doSome(list2);
var list3 = new ArrayList<Parent1>();
doSome(list3);
}
{
var list1 = new ArrayList<superParent>();
❌doSome(list1);
var list2 = new ArrayList<superParentInterface>();
❌doSome(list2);
var list3 = new ArrayList<superParent1>();
❌doSome(list3);
}
{
var list1 = new ArrayList<Uncle>();
❌doSome(list1);
var list2 = new ArrayList<Uncle1>();
❌doSome(list2);
var list3 = new ArrayList<UncleInterface>();
❌doSome(list3);
}
{
var list = new ArrayList<Object>();
❌doSome(list);
}
}
public static void doSome(List<? extends ParentInterface > list) {
//不能修改增加元素,但是可以删除元素
//因为虽然有上界了,但是还是无法确定 list 的元素类型 是 Parent 或 Parent1 ,还是Parent的 子类 Child1 或 Child2 等子类
❌list.add(new Parent());
❌list.add(new Parent1());
❌list.add(new Child1());
❌list.add(new Child2());
❌list.add(new Object());
for (Parent item: list) {
System.out.println(item + ";");
}
}
}
如图中蓝色框的是上界通配符限制的范围,它限制了上界的边界,下界不限制,只要是子类就可以,子类就会有很多分叉
下界通配符
下界通配符,用来指定范围的下边界堵住往下的路,但是往上的路虽然没有堵,但是进行了限制。传入的类型只能是Child1(下边界) 及其父类的父类 等 Parent ,它的语法形式为:<? super Child1>
class GenericsType {
public static void main(String[] args) {
{
var list1 = new ArrayList<Child1>();
doSome(list1);
var list2 = new ArrayList<Child2>();
❌doSome(list2);
}
{
var list1 = new ArrayList<Son1>();
❌doSome(list1);
var list2 = new ArrayList<Son2>();
❌doSome(list2);
}
{
var list1 = new ArrayList<Parent>();
doSome(list1);
var list2 = new ArrayList<ParentInterface>();
doSome(list2);
var list3 = new ArrayList<Parent1>();
❌doSome(list3);
}
{
var list1 = new ArrayList<superParent>();
doSome(list1);
var list2 = new ArrayList<superParentInterface>();
doSome(list2);
var list3 = new ArrayList<superParent1>();
❌doSome(list3);
}
{
var list1 = new ArrayList<Uncle>();
❌doSome(list1);
var list2 = new ArrayList<Uncle1>();
❌doSome(list2);
var list3 = new ArrayList<UncleInterface>();
❌doSome(list3);
}
{
var list = new ArrayList<Object>();
doSome(list);
}
}
public static void doSome(List<? super Child1> list) {
//这里可以肯定的是 list 里的元素类型不是 Parent及父类 就是 Child1 这俩种类型
//所以插入 Child1 及其子类型是肯定安全的
list.add(new Child1());
list.add(new Son1());
//因为 list 的元素类型有可能是 Child1 ,插入 Parent 会发生类型转换错误,
//在往上插入就更不安全了
❌list.add(new Parent());
}
}
如图中蓝色框的是下界通配符限制的范围,它限制了下界,上界的顶不限制,但是只能沿着父类父类方向,而且不能有分叉
泛型的反射
一个类可以继承自一个泛型类。例如:父类的类型是Pair
public class IntPair extends Pair<Integer> {
}
我们无法获取Pair
因为Java引入了泛型,所以,只用Class来标识类型已经不够了。实际上,Java的类型系统结构如下:
graph TB
Type -->Class
Type -->ParameterizedType
Type -->GenericArrayType
Type -->WildcardType
Type -->TypeVariable
Type直接子接口: ParameterizedType,GenericArrayType,TypeVariable和WildcardType四种类型的接口
- ParameterizedType: 表示一种参数化的类型,比如Collection
- GenericArrayType: 表示一种元素类型是参数化类型或者类型变量的数组类型
- TypeVariable: 是各种类型变量的公共父接口
- WildcardType: 代表一种通配符类型表达式,比如?, ? extends Number, ? super Integer【wildcard是一个单词:就是“通配符”】
参数化类型 ParameterizedType
/**
* 参数化泛型
*/
public interface ParameterizedType extends Type {
/**
* 这个 Type 类型的参数的实际类型数组。 如 Map<String,Person> map
这个ParameterizedType 返回的是 String 类,Person 类的全限定类名的 Type Array。
*/
Type[] getActualTypeArguments();
/**
* 返回的是当前这个 ParameterizedType 的类型。 如 Map<String,Person> map
这个ParameterizedType 返回的是 Map 类的全限定类名的 Type Array。
*/
Type getRawType();
/**
*(可以简单理解为:外部类与内部类的关系,此操作为获取该对象(内部类)的外部类)
*/
Type getOwnerType();
}
class GenericsTypeDemo<T1,T2> { }
class TypeDemo extends GenericsPair<Integer,String> { }
class GenericsType {
public static void main(String[] args){
{
var type = TypeDemo.class.getGenericSuperclass();
if (type instanceof ParameterizedType) {
var pt = (ParameterizedType) type;
System.out.println(pt.getTypeName());
// class com.hank.genericity.Pair
System.out.println(pt.getRawType());
// com.hank.genericity.Pair<java.lang.Integer, java.lang.String>
//获取内部类的外部持有者
System.out.println(pt.getOwnerType());
// null
//获选泛型类的泛型参数
var types = pt.getActualTypeArguments();
Arrays.stream(types).forEach(p -> {
System.out.println(p.getTypeName());
//java.lang.Integer
//java.lang.String
});
}
}
}
}
参数化范型数组类型 GenericArrayType
public interface GenericArrayType extends Type {
//获取泛型数组的参数类型
Type getGenericComponentType();
}
GenericArrayType 如果类内不保存泛型参数类型,这些参数化类型信息就会丢失
class GenericArrayTypeDemo<T> {
List<String>[] pTypeArray;
//类型名java.util.List<java.lang.String>[]
//泛型数组参数类型java.util.List<java.lang.String>
T[] vTypeArray;
//类型名T[]
//泛型数组参数类型T
Person<String, Integer>[] persons;
//类型名com.hank.genericity.Person<java.lang.String, java.lang.Integer>[]
//泛型数组参数类型com.hank.genericity.Person<java.lang.String, java.lang.Integer>
//不属于
String[] strings;
public void doSome(List<String>[] pTypeArray){
//类型名java.util.List<java.lang.String>[]
//泛型数组参数类型java.util.List<java.lang.String>
}
}
//
class GenericsType {
public static void main(String[] args) throws NoSuchMethodException, ClassNotFoundException {
var fields = GenericArrayTypeDemo.class.getDeclaredFields();
Arrays.stream(fields).forEach(p->{
var type = p.getGenericType();
if(type instanceof GenericArrayType){
var genericArrayType=(GenericArrayType) type;
System.out.println("类型名"+genericArrayType.getTypeName());
System.out.println("泛型数组参数类型"+genericArrayType.getGenericComponentType());
}
});
List<String>[] pTypeArray=new List[0];
var clazz = pTypeArray.getClass();
var methods = GenericArrayTypeDemo.class.getMethod("doSome",clazz);
var types=methods.getGenericParameterTypes();
Arrays.stream(types).forEach(p->{
if(p instanceof GenericArrayType){
var genericArrayType=(GenericArrayType) p;
System.out.println("类型名"+genericArrayType.getTypeName());
System.out.println("泛型数组参数类型"+genericArrayType.getGenericComponentType());
}
});
}
}
参数化范型 type 类型 TypeVariable
/**
* TypeVariable
*/
public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
/**
* 得到上边界的 Type数组,如 K 的上边界数组是 InputStream 和 Serializable。 V 没有指定的话,
* 上边界是 Object
*/
Type[] getBounds();
/**
* 返回的是声明这个 Type 所在的类 的 Type
*/
D getGenericDeclaration();
/**
* 返回的是这个 type variable 的名称
*/
String getName();
/**
* AnnotatedType表示当前在此VM中运行的程序中可能注释使用的类型。
该用途可以是Java编程语言中的任何类型,包括数组类型,参数化类型,类型变量或通配符类型。
* 通过AnnotatedType的getType()方法,获得其上边界的 Type,如 K 的上边界数组是 InputStream 和
Serializable。
V 没有指定的话,上边界是 Object
*/
AnnotatedType[] getAnnotatedBounds();
}
class Person<T> {
}
class GenericArrayTypeDemo<T extends Person<T> & Serializable,V> {
T t;
/**
type variable:T
type variable 的上边界:com.hank.genericity.Person<T>;java.io.Serializable
Type 所在的类 的 Type:class com.hank.genericity.GenericArrayTypeDemo
*/
V v;
/**
type variable:V
type variable 的上边界:java.lang.Object //不指定上边界就是 object
Type 所在的类 的 Type:class com.hank.genericity.GenericArrayTypeDemo
*/
//不属于 TypeVariable
V[] values;
String str;
}
class GenericsType {
public static void main(String[] args) throws NoSuchMethodException, ClassNotFoundException {
var fields = GenericArrayTypeDemo.class.getDeclaredFields();
Arrays.stream(fields).forEach(p->{
var type = p.getGenericType();
if(type instanceof TypeVariable){
var typeVariable=(TypeVariable) type;
System.out.println("type variable:"+typeVariable.getName());
var arr= Arrays.stream(typeVariable.getBounds()).map(q->q.getTypeName()).
collect(Collectors.toList());
System.out.println("type variable 的上边界:"+ String.join(";",arr));
System.out.println("Type 所在的类 的 Type:"+typeVariable.getGenericDeclaration());
}
});
}
}
通配符泛型类 WildcardType
public interface WildcardType extends Type {
/**
* 上边界
*/
Type[] getUpperBounds();
/**
* 下边界
*/
Type[] getLowerBounds();
}
class GenericArrayTypeDemo {
List<? extends Number> list1;
/**
* 上边界:java.lang.Number
* 下边界:
*/
List< ? super String> list2;
/**
* 上边界:java.lang.Object
* 下边界:java.lang.String
*/
List< ? > list3;
/**
* 上边界:java.lang.Object
* 下边界:
*/
}
class GenericsType {
public static void main(String[] args) throws NoSuchMethodException, ClassNotFoundException {
var fields = GenericArrayTypeDemo.class.getDeclaredFields();
Arrays.stream(fields).forEach(p->{
//先获取参数话类型
var type = p.getGenericType();
if(type instanceof ParameterizedType){
var parameterizedType=(ParameterizedType) type;
var arg0= parameterizedType.getActualTypeArguments()[0];
//在获取通配符类型
if(arg0 instanceof WildcardType ){
var wildcardType=(WildcardType) arg0;
var arr= Arrays.stream(wildcardType.getUpperBounds()).
map(q->q.getTypeName()).collect(Collectors.toList());
System.out.println("上边界:"+ String.join(";",arr));
var arr1= Arrays.stream(wildcardType.getLowerBounds()).
map(q->q.getTypeName()).collect(Collectors.toList());
System.out.println("下边界:"+ String.join(";",arr1));
}
}
});
}
}
Spring 对泛型反射的封装 ResolvableType
提供方便的API,如下:
- ResolvableType.forClass
- ResolvableType.forMethodParameter
- ResolvableType.forMethodReturnType
- ResolvableType.forField
- ResolvableType.forConstructorParameter
获取父类的泛型
resolvedType.getSuperType() 获取泛型父类型
class GenericsType {
static class Person<T, V> {}
static class Student extends Person<String, Integer> {}
public static void main(String[] args) throws NoSuchMethodException, ClassNotFoundException {
//用JDK 的方式获取
var type =Student.class.getGenericSuperclass();
if(type instanceof ParameterizedType){
var parameterizedType =(ParameterizedType)type;
Arrays.stream(parameterizedType.getActualTypeArguments()).forEach(p->{
var name = p.getTypeName();
System.out.println(name);
/**
* java.lang.String
* java.lang.Integer
*/
});
}
// ResolvableType 的 API getSuperType 实现
var resolvedType = ResolvableType.forClass(Student.class);
Arrays.stream(resolvedType.getSuperType().getGenerics()).forEach(p->{
var aClass=p.resolve();
System.out.println(aClass.getName());
/**
* java.lang.String
* java.lang.Integer
*/
});
}
}
获取接口上的泛型
resolvedType.getInterfaces() 实现获取泛型接口
class GenericsType {
static interface Person<T, V> {}
static class Student implements Person<String, Integer> {}
public static void main(String[] args){
//用JDK 的方式获取
var type =Student.class.getGenericInterfaces();
if(type[0] instanceof ParameterizedType){
var parameterizedType =(ParameterizedType)type[0];
Arrays.stream(parameterizedType.getActualTypeArguments()).forEach(p->{
var name = p.getTypeName();
System.out.println(name);
/**
* java.lang.String
* java.lang.Integer
*/
});
}
// ResolvableType 的 API getInterfaces 实现
var resolvedType = ResolvableType.forClass(Student.class);
Arrays.stream(resolvedType.getInterfaces()[0].getGenerics()).forEach(p->{
var aClass=p.resolve();
System.out.println(aClass.getName());
/**
* java.lang.String
* java.lang.Integer
*/
});
}
}
获取属性上的泛型
class GenericsType {
private List<String> listString;
private List<List<String>> listLists;
private Map<String, Long> maps;
public static void main(String[] args) {
//用JDK 的方式获取
Arrays.stream(GenericsType.class.getDeclaredFields()).forEach(p->{
var type = p.getGenericType();
if(type instanceof ParameterizedType){
var parameterizedType = (ParameterizedType) type;
Arrays.stream(parameterizedType.getActualTypeArguments()).forEach(q->{
//嵌套的要自己处理
if(q instanceof ParameterizedType){
var parameterizedType1 =(ParameterizedType) q;
Arrays.stream(parameterizedType1.getActualTypeArguments()).forEach(l->{
System.out.println(l.getTypeName());
});
}else {
System.out.println(q.getTypeName());
}
});
}
});
/**
* java.lang.String
* java.lang.String
* java.lang.String
* java.lang.Long
*/
// ResolvableType 的 API ResolvableType.forField
Arrays.stream(GenericsType.class.getDeclaredFields()).forEach(p->{
var resolvedType =
ResolvableType.forField(ReflectionUtils.findField(GenericsType.class,p.getName()));
Arrays.stream(resolvedType.getGenerics()).forEach(q->{
//嵌套的要自己处理
if(q.getGenerics().length>0){
Arrays.stream(q.getGenerics()).forEach(l->{
var aClass=l.resolve();
System.out.println(aClass.getTypeName());
});
}else{
var aClass=q.resolve();
System.out.println(aClass.getTypeName());
}
});
});
/**
* java.lang.String
* java.lang.String
* java.lang.String
* java.lang.Long
*/
}
}
获取属性上的通配符泛型边界
class GenericsType {
private List<? extends Number> list;
public static void main(String[] args) {
//用JDK 的方式获取
Arrays.stream(GenericsType.class.getDeclaredFields()).forEach(p -> {
var type = p.getGenericType();
if (type instanceof ParameterizedType) {
var parameterizedType = (ParameterizedType) type;
Arrays.stream(parameterizedType.getActualTypeArguments()).forEach(q -> {
//嵌套的要自己处理
if (q instanceof WildcardType) {
var wildcardType = (WildcardType) q;
System.out.println(wildcardType.getTypeName());
var arr = Arrays.stream(wildcardType.getUpperBounds()).map(n -> n.getTypeName()).
collect(Collectors.toList());
System.out.println("上边界:" + String.join(";", arr));
var arr1 = Arrays.stream(wildcardType.getLowerBounds()).map(n -> n.getTypeName()).
collect(Collectors.toList());
System.out.println("下边界:" + String.join(";", arr1));
} else {
System.out.println(q.getTypeName());
}
});
}
});
/**
* ? extends java.lang.Number
* 上边界:java.lang.Number
* 下边界:
*/
// ResolvableType 的 API ResolvableType.forField
Arrays.stream(GenericsType.class.getDeclaredFields()).forEach(p -> {
var resolvedType =
ResolvableType.forField(ReflectionUtils.findField(GenericsType.class, p.getName()));
Arrays.stream(resolvedType.getGenerics()).forEach(q -> {
var type = q.getType();
if (type instanceof WildcardType) {
var wildcardType = (WildcardType) type;
System.out.println(wildcardType.getTypeName());
var arr = Arrays.stream(wildcardType.getUpperBounds()).map(n -> n.getTypeName()).
collect(Collectors.toList());
System.out.println("上边界:" + String.join(";", arr));
var arr1 = Arrays.stream(wildcardType.getLowerBounds()).map(n -> n.getTypeName()).
collect(Collectors.toList());
System.out.println("下边界:" + String.join(";", arr1));
} else {
System.out.println(type.getTypeName());
}
});
});
/**
* ? extends java.lang.Number
* 上边界:java.lang.Number
* 下边界:
*/
}
}