Java高级之泛型体系知识学习

简介: Type 是 Java 语言中所有类型的公共父接口,其从 JDK5 开始引入,引入的目的主要是为了支持泛型。Java的泛型体系还是比较复杂的, 不过没关系,本篇文章会从实战的角度来,学习泛型。

一、Java泛型体系

Type 是 Java 语言中所有类型的公共父接口,其从 JDK5 开始引入,引入的目的主要是为了支持泛型。
Java的泛型体系还是比较复杂的, 不过没关系,本篇文章会从实战的角度来,学习泛型。

1.1 ParameterizedType 参数化泛型

ParameterizedType 是, 参数化泛型只要记住凡是带泛型的是明确的类型,只要不是数组GenericArrayType那么一定是ParameterizedType。
如下:

  • List<?> list 中的 list
  • Map<String,String> map中的map
  • Map<String,String> map中的map

1.1.1 API 说明

ParameterizedType 一共有3个方法如下。

public interface ParameterizedType extends Type {
    // 获取泛型信息,输一个数组。因为可能泛型有多个
    Type[] getActualTypeArguments();
    // 原始数据类型
    Type getRawType();
    // 
    Type getOwnerType();
}
  • getRawType 获取原始数据类型
  • getActualTypeArguments 获取泛型信息,因为泛型可以是多个,所以返回是数组

1.1.2 代码示例

public class Test {
    class Girl implements Person {}
    class Boy implements Person {}
    interface Person {}
    class School<A extends Boy & Person> {}
    School<Boy> boySchool;
    School<Boy>[] schools;
    @Test
    public void test() {
        // class java.lang.Class
        System.out.println(ReflectionUtils.findField(Test.class, "boy").getGenericType().getClass());
        // class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
        System.out.println(ReflectionUtils.findField(Test.class, "boySchool").getGenericType().getClass());
        // class sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl
        System.out.println(ReflectionUtils.findField(Test.class, "schools").getGenericType().getClass());
    }
}
  • boy 是具体类型,且不是泛型,所以是Class类型
  • School<Boy> boySchool 是具体类型,但是有泛型<Boy>,所以是ParameterizedType

    • ParameterizedType#getActualTypeArguments 下标0就是泛型Boy
  • School<Boy>[] schools 是具体类型,有泛型<Boy>,但是是数组类型所以是GenericArrayType

1.2 GenericArrayType 泛型数组

GenericArrayTypeParameterizedType是比较类似的,唯一的区别是GenericArrayType一定是数组,如果不是数组就是ParameterizedType

1.2.1 API 说明

GenericArrayType 只提供了一个方法就是获取泛型的方法

public interface GenericArrayType extends Type {
    // 获取数组泛型
    Type getGenericComponentType();
}

1.2.2 代码示例

public class Test {
    class Girl implements Person {}
    class Boy implements Person {}
    interface Person {}
    class School<A extends Boy & Person> {}
    School<Boy> boySchool;
    School<Boy>[] schools;
    @Test
    public void test2(){
        GenericArrayType schoolsArrayType = (GenericArrayType) ReflectionUtils.findField(Test.class, "schools").getGenericType();
        Type genericComponentType = schoolsArrayType.getGenericComponentType();
        // learn.common.print.Test$School<learn.common.print.Test$Boy>
        System.out.println(genericComponentType.getTypeName());
        // class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
        System.out.println(genericComponentType.getClass());
    }
}  
  • School<Boy> boySchool 是具体类型,且有泛型,但是不是数组所以是ParameterizedType
  • School<Boy>[] schools 是具体类型,且有泛型,但是数组所以就是GenericArrayType

    • GenericArrayType#getGenericComponentType = School<Boy> = ParameterizedType

1.3 TypeVariable 泛型变量

TypeVariable变量泛型是比较好判断的,只要是变量泛型。一定就是TypeVariable。

1.3.1 API 说明

public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
    // 获取泛型信息
    Type[] getBounds();

    D getGenericDeclaration();

    String getName();

    AnnotatedType[] getAnnotatedBounds();
}

1.3.2 代码示例

    class TypeVariableObj<A extends Number> {
        A a;
        TypeVariableObj<A> as;
    }
    @Test
    public void test3() {
        Type a = ReflectionUtils.findField(TypeVariableObj.class, "a").getGenericType();
        // class sun.reflect.generics.reflectiveObjects.TypeVariableImpl
        System.out.println(a.getClass());

        Type as = ReflectionUtils.findField(TypeVariableObj.class, "as").getGenericType();
        // class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
        System.out.println(as.getClass());
        Type[] actualTypeArguments = ((ParameterizedType) as).getActualTypeArguments();
        // A 因为只有1个泛型,所以直接去下标0
        TypeVariable actualTypeArgument = (TypeVariable) actualTypeArguments[0];
        System.out.println(actualTypeArgument.getTypeName());
    }
  • A a = TypeVariable
  • TypeVariableObj<A> as = ParameterizedType

    • ParameterizedType#getActualTypeArguments()[0] = <A>

1.4 WildcardType 泛型表达式

WildcardType也比较好判断只要是通配符,可以简单理解,直接带有 ? 的泛型限定那么就是 WildcardType

1.4.1 API 说明

WildcardType通配符, 如 ?, ? extends Number, ? super Integer

public interface WildcardType extends Type {
    // 泛型上限
    Type[] getUpperBounds();
    // 泛型下限
    Type[] getLowerBounds();
}
  • Type[] getUpperBounds(); //获得泛型表达式上界(上限) 获取泛型变量的上边界(extends)
  • Type[] getLowerBounds(); //获得泛型表达式下界(下限) 获取泛型变量的下边界(super)

1.4.2 代码示例

public class WildcardTypeTest {
    Map<? extends String, ? super Number> map;
    @Test
    public void wildcardTypeTest() {
        Field map = ReflectionUtils.findField(WildcardTypeTest.class, "map");
        Type[] actualTypeArguments = ((ParameterizedType) map.getGenericType()).getActualTypeArguments();
        // ? extends java.lang.String
        System.out.println(((WildcardType) actualTypeArguments[0]).getTypeName());
        // class java.lang.String
        System.out.println(((WildcardType) actualTypeArguments[0]).getUpperBounds()[0]);
    }
}
  • Map<? extends String, ? super Number> map 中 map是 ParameterizedType

    • ParameterizedType#getActualTypeArguments[0] = WildcardType#getUpperBounds[0] = String
    • ParameterizedType#getActualTypeArguments[1] = WildcardType#getLowerBounds[0] = Number

二、泛型获取

通过上面的学习,我们可以使用原始API来获取各种泛型的信息,而Spring中有一个比较好用的工具。屏蔽了底层的
具体实现。比较方便。

2.1 获取接口泛型

    class A {}
    class B {}
    interface School<T, K> {}
    interface X extends School<A, B> {}
    @Test
    public void test() {
        // 获取实现的接口是泛型的信息
        ResolvableType resolvableType = ResolvableType.forClass(X.class);
        Class<?> resolve1 = resolvableType.getInterfaces()[0].getGeneric(0).resolve();
        // class learn.common.print.ColorConsoleTest$A
        System.out.println(resolve1);
        Class<?> resolve2 = resolvableType.getInterfaces()[0].getGeneric(1).resolve();
        // class learn.common.print.ColorConsoleTest$B
        System.out.println(resolve2);
    }

2.2 获取父类泛型

    class A {}
    class B {}
    class School<T, K> {}
    class X extends School<A, B> {}
    @Test
    public void test() {
        // 获取实现的接口是泛型的信息
        ResolvableType resolvableType = ResolvableType.forClass(X.class);
        Class<?> resolve1 = resolvableType.getSuperType().getGeneric(0).resolve();
        // class learn.common.print.ColorConsoleTest$A
        System.out.println(resolve1);
        Class<?> resolve2 = resolvableType.getSuperType().getGeneric(1).resolve();
        // class learn.common.print.ColorConsoleTest$B
        System.out.println(resolve2);
    }

2.3 获取字段泛型

    class A {}
    class B {}
    class School<T, K> {}
    class X {
        private School<A, B> school;
    }

    @Test
    public void test() {
        // Spring的提供工具类,用于字段的泛型信息,Person<String>
        ResolvableType resolvableType = ResolvableType.forField(Objects.requireNonNull(ReflectionUtils.findField(X.class, "school")));
        System.out.println(resolvableType);
        Class<?> resolve1 = resolvableType.getGeneric(0).resolve();
        // class learn.common.print.ColorConsoleTest$A
        System.out.println(resolve1);
        Class<?> resolve2 = resolvableType.getGeneric(1).resolve();
        // class learn.common.print.ColorConsoleTest$B
        System.out.println(resolve2);
    }

2.4 获取方法泛型

    class A {}
    class B {}
    class School<T, K> {}
    class X {
        public School<A, B> getSchool() {
            return null;
        }
    }

    @Test
    public void test() {
        // Spring的提供工具类,用于字段的泛型信息,Person<String>
        ResolvableType resolvableType = ResolvableType.forMethodReturnType(Objects.requireNonNull(ReflectionUtils.findMethod(X.class, "getSchool")));
        System.out.println(resolvableType);
        Class<?> resolve1 = resolvableType.getGeneric(0).resolve();
        // class learn.common.print.ColorConsoleTest$A
        System.out.println(resolve1);
        Class<?> resolve2 = resolvableType.getGeneric(1).resolve();
        // class learn.common.print.ColorConsoleTest$B
        System.out.println(resolve2);
    }
相关文章
|
2月前
|
XML Java 编译器
Java学习十六—掌握注解:让编程更简单
Java 注解(Annotation)是一种特殊的语法结构,可以在代码中嵌入元数据。它们不直接影响代码的运行,但可以通过工具和框架提供额外的信息,帮助在编译、部署或运行时进行处理。
91 43
Java学习十六—掌握注解:让编程更简单
|
22天前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
2月前
|
存储 SQL 小程序
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
这篇文章详细介绍了Java虚拟机(JVM)的运行时数据区域和JVM指令集,包括程序计数器、虚拟机栈、本地方法栈、直接内存、方法区和堆,以及栈帧的组成部分和执行流程。
36 2
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
|
1月前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
2月前
|
Java API
[Java]泛型
本文详细介绍了Java泛型的相关概念和使用方法,包括类型判断、继承泛型类或实现泛型接口、泛型通配符、泛型方法、泛型上下边界、静态方法中使用泛型等内容。作者通过多个示例和测试代码,深入浅出地解释了泛型的原理和应用场景,帮助读者更好地理解和掌握Java泛型的使用技巧。文章还探讨了一些常见的疑惑和误区,如泛型擦除和基本数据类型数组的使用限制。最后,作者强调了泛型在实际开发中的重要性和应用价值。
26 0
[Java]泛型
|
2月前
|
存储 安全 Java
🌱Java零基础 - 泛型详解
【10月更文挑战第7天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
15 1
|
2月前
|
小程序 Oracle Java
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
这篇文章是关于JVM基础知识的介绍,包括JVM的跨平台和跨语言特性、Class文件格式的详细解析,以及如何使用javap和jclasslib工具来分析Class文件。
49 0
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
|
2月前
|
存储 算法 Java
带你学习java的数组军队列
带你学习java的数组军队列
35 0
|
2月前
|
Java 大数据 开发工具
java学习——环境准备(1)
java学习——环境准备(1)
42 0
|
2月前
|
安全 Java 编译器
Java基础-泛型机制
Java基础-泛型机制
16 0