随着泛型用的越来越多,获取泛型实际类型信息的需求也会出现,如果用原生API,需要很多步操作才能获取到泛型,比如:
- ParameterizedType parameterizedType =
- (ParameterizedType) ABService.class.getGenericInterfaces()[0];
- Type genericType = parameterizedType.getActualTypeArguments()[1];
Spring提供的ResolvableType API,提供了更加简单易用的泛型操作支持,如:
- ResolvableType resolvableType1 = ResolvableType.forClass(ABService.class);
- resolvableType1.as(Service.class).getGeneric(1).resolve()
对于获取更复杂的泛型操作ResolvableType更加简单。
假设我们的API是:
- public interface Service<N, M> {
- }
- @org.springframework.stereotype.Service
- public class ABService implements Service<A, B> {
- }
- @org.springframework.stereotype.Service
- public class CDService implements Service<C, D> {
- }
如上泛型类非常简单。
1、得到类型的泛型信息
- ResolvableType resolvableType1 = ResolvableType.forClass(ABService.class);
通过如上API,可以得到类型的ResolvableType,如果类型被Spring AOP进行了CGLIB代理,请使用ClassUtils.getUserClass(ABService.class)得到原始类型。
可以通过如下得到泛型参数的第1个位置(从0开始)的类型信息
- resolvableType1.getInterfaces()[0].getGeneric(1).resolve()
因为我们泛型信息放在 Service<A, B> 上,所以需要resolvableType1.getInterfaces()[0]得到;
通过getGeneric(泛型参数索引)得到某个位置的泛型;
resolve()把实际泛型参数解析出来
2、得到字段级别的泛型信息
假设我们的字段如下:
- @Autowired
- private Service<A, B> abService;
- @Autowired
- private Service<C, D> cdService;
- private List<List<String>> list;
- private Map<String, Map<String, Integer>> map;
- private List<String>[] array;
通过如下API可以得到字段级别的ResolvableType
- ResolvableType resolvableType2 =
- ResolvableType.forField(ReflectionUtils.findField(GenricInjectTest.class, "cdService"));
然后通过如下API得到Service<C, D>的第0个位置上的泛型实参类型,即C
- resolvableType2.getGeneric(0).resolve()
比如 List<List<String>> list;是一种嵌套的泛型用例,我们可以通过如下操作获取String类型:
- ResolvableType resolvableType3 =
- ResolvableType.forField(ReflectionUtils.findField(GenricInjectTest.class, "list"));
- resolvableType3.getGeneric(0).getGeneric(0).resolve();
更简单的写法
- resolvableType3.getGeneric(0, 0).resolve(); //List<List<String>> 即String
比如Map<String, Map<String, Integer>> map;我们想得到Integer,可以使用:
- ResolvableType resolvableType4 =
- ResolvableType.forField(ReflectionUtils.findField(GenricInjectTest.class, "map"));
- resolvableType4.getGeneric(1).getGeneric(1).resolve();
更简单的写法
- resolvableType4.getGeneric(1, 1).resolve()
3、得到方法返回值的泛型信息
假设我们的方法如下:
- private HashMap<String, List<String>> method() {
- return null;
- }
得到Map中的List中的String泛型实参:
- ResolvableType resolvableType5 =
- ResolvableType.forMethodReturnType(ReflectionUtils.findMethod(GenricInjectTest.class, "method"));
- resolvableType5.getGeneric(1, 0).resolve();
4、得到构造器参数的泛型信息
假设我们的构造器如下:
- public Const(List<List<String>> list, Map<String, Map<String, Integer>> map) {
- }
我们可以通过如下方式得到第1个参数( Map<String, Map<String, Integer>>)中的Integer:
- ResolvableType resolvableType6 =
- ResolvableType.forConstructorParameter(ClassUtils.getConstructorIfAvailable(Const.class, List.class, Map.class), 1);
- resolvableType6.getGeneric(1, 0).resolve();
5、得到数组组件类型的泛型信息
如对于private List<String>[] array; 可以通过如下方式获取List的泛型实参String:
- ResolvableType resolvableType7 =
- ResolvableType.forField(ReflectionUtils.findField(GenricInjectTest.class, "array"));
- resolvableType7.isArray();//判断是否是数组
- resolvableType7.getComponentType().getGeneric(0).resolve();
6、自定义泛型类型
- ResolvableType resolvableType8 = ResolvableType.forClassWithGenerics(List.class, String.class);
- ResolvableType resolvableType9 = ResolvableType.forArrayComponent(resolvableType8);
- resolvableType9.getComponentType().getGeneric(0).resolve();
ResolvableType.forClassWithGenerics(List.class, String.class)相当于创建一个List<String>类型;
ResolvableType.forArrayComponent(resolvableType8);:相当于创建一个List<String>[]数组;
resolvableType9.getComponentType().getGeneric(0).resolve():得到相应的泛型信息;
7、泛型等价比较:
- resolvableType7.isAssignableFrom(resolvableType9)
如下创建一个List<Integer>[]数组,与之前的List<String>[]数组比较,将返回false。
- ResolvableType resolvableType10 = ResolvableType.forClassWithGenerics(List.class, Integer.class);
- ResolvableType resolvableType11= ResolvableType.forArrayComponent(resolvableType10);
- resolvableType11.getComponentType().getGeneric(0).resolve();
- resolvableType7.isAssignableFrom(resolvableType11);
从如上操作可以看出其泛型操作功能十分完善,尤其在嵌套的泛型信息获取上相当简洁。目前整个Spring4环境都使用这个API来操作泛型信息。
如之前说的泛型注入:Spring4新特性——泛型限定式依赖注入,通过在依赖注入时使用如下类实现:
GenericTypeAwareAutowireCandidateResolver
QualifierAnnotationAutowireCandidateResolver
ContextAnnotationAutowireCandidateResolver
还有如Spring的核心BeanWrapperImpl,以及整个Spring/SpringWevMVC的泛型操作都是替换为这个API 了:GenericCollectionTypeResolver和GenericTypeResolver都直接委托给ResolvableType这 个API。
所以大家以后对泛型操作可以全部使用这个API了,非常好用。测试用例请参考GenricInjectTest.java。
相关推荐
在Spring4框架中,开发者们迎来了一项重要的更新——更优的Java泛型操作API。这一新特性极大地提升了代码的可读性和可维护性,同时也为开发者提供了更强大的工具来处理泛型类型。本文将深入探讨Spring4在这个领域所...
SSH泛型代码实例是关于Java编程中的一种常见技术——Spring、Struts和Hibernate(SSH)框架结合使用泛型的应用示例。泛型是Java SE 5.0引入的一个重要特性,它允许在编译时检查类型安全,并且所有的强制转换都是自动...
学习和熟练运用这些Java类库,不仅能够提升编程效率,还能帮助开发者更好地理解和应用Java的特性。对于初学者,可以通过阅读API文档、实践项目和参考书籍来逐步掌握这些知识。同时,不断更新的Java版本会引入新的...
Spring 3.0 针对Java 5做了全面的升级,这意味着它充分利用了Java 5中的新特性,如泛型、枚举类型等。这些新特性不仅提高了代码的可读性和可维护性,还增加了编译时的安全检查。 ##### 5. Java 基于元数据的配置 ...
10. **泛型**: 泛型增强了代码的类型安全性,允许在编译时检查类型,并提供了更好的代码重用。 11. **注解(Annotation)**: 注解提供了一种向编译器或JVM提供元数据的方式,常用于配置框架(如Spring)或实现元编程...
15. **Java 8及以后的新特性**:如Lambda表达式、Stream API、Optional类等,这些新特性极大地提高了Java的编程效率。 以上只是Java知识体系的一小部分,实际的面试可能会涉及到更多细节,如JDK源码分析、性能调优...
Spring 2.0提供了一系列更新的示例应用程序,帮助开发者更好地理解新特性的使用方法。 **2.9 文档改进** Spring 2.0的官方文档得到了大幅改进,提供了更加详尽的指南和教程,以帮助开发者快速上手。 #### 三、...
14. **Java 8及以后的新特性**:Java 8引入了Lambda表达式、函数式接口、Stream API等新特性,提高了代码简洁性和效率;Java 11及更高版本也有新的改进和增强。 "Java精华(水木清华站)"可能涵盖以上部分或全部内容...
Java编程语言自1995年发布以来,一直以其跨平台、面向对象和安全性等特点深受开发者喜爱。在Java的学习和实践中,经常会遇到一些经典问题,这些问题不仅有助于...通过深入学习和实践,可以更好地掌握Java编程的精髓。
最后,为了更好地准备面试和提升学习效率,可以参考作者提到的免费分享的Java学习路线文档,涵盖相关知识点的题目和解答。通过系统的学习和实践,你将能更全面地掌握Java,增加自己在竞争激烈的就业市场中的优势。祝...
在Spring 2.5版本中,dist.jar进一步强化了对Java 5特性的支持,如注解(Annotations)、泛型(Generics)等,显著提升了代码的可读性和可维护性。 dist.jar包含的主要模块有: 1. **IoC容器**:Spring的IoC容器是...
在IO流方面,NIO(New IO)在Java 5.0中被引入,提供了一种基于通道(Channel)和缓冲区(Buffer)的I/O模型,相比于传统的流模型,NIO具有更好的非阻塞和选择器特性,适合处理大量并发连接。 最后,JDK 5.0对日期...
6. **改进的类型推断**:编译器可以更好地推断泛型的类型,减少了类型声明的需要。 7. **Nashorn JavaScript引擎**:JDK 8包含了Nashorn JavaScript引擎,可以直接在Java应用中执行JavaScript代码。 **安装与配置:...
4. Java集合框架:对List、Set、Map等集合的实现类及其特性有深入了解,包括它们的数据结构、排序和搜索机制。 5. 并发编程:理解线程的创建和运行机制、线程安全、同步机制(synchronized、lock)、死锁、线程池的...
此外,还应该了解Java反射机制,并熟悉Java 1.5之后引入的新特性,如泛型等。 #### 二、JAVA网络编程 在掌握了Java语言基础后,接下来可以进一步学习Java在网络编程方面的应用,这包括但不限于以下内容: - **...
在Java中,包(package)是一种组织类和接口的方式,帮助避免命名冲突并提供更好的代码管理。 1. **javax**: 这个包通常包含Java扩展框架的一部分,其中包含了标准Java库没有提供的额外功能,如JavaBeans、Java...
另外,Jackson库本身也在不断更新和发展,新版本引入了更多优化和特性,例如支持JSON-P(JSR 353)和JSON-B(JSR 367),以及对Java 8新特性的支持。 综上所述,`jackson-mapper-asl-1.9.12.jar`是Java开发中处理...
根据提供的文件信息,我们可以将SCJP(Sun Certified Java Programmer)的大纲内容进行详细的解析与扩展。...以上内容是根据SCJP大纲整理的详细知识点概述,希望能够帮助学习者更好地理解和掌握Java的核心概念与技术。
1. **J2SE基础**:首先,你需要掌握Java的基础,包括面向对象编程的三大特性——封装、继承和多态。理解内存分析、递归、集合类(如ArrayList、HashMap)、泛型、自动装箱与拆箱以及注解(Annotation)。此外,还...