guava:基于TypeToken解析泛型类的类型变量(TypeVariable)的具体类型

对于 Base<F,T>这样的带泛型参数的抽象类,如何在类初始化时得到F,T对应的类型?

Guava TypeToken是一个功能强大的泛型解析工具。可以很简单的实际这个需求。

如下一行代码就可以完成解析:

java 复制代码
Type resolved = new TypeToken<F>(getClass()) {}.getType();

在执行 TypeToken(Class<?> declaringClass)构造方法时已经完成了对F类型参数的解析,保存到runtimeType字段。如下为 TypeToken(Class<?> declaringClass)构造方法的代码:

java 复制代码
  /**
   * 这里declaringClass必须为声明类型变量的类
   */
  protected TypeToken(Class<?> declaringClass) {
    Type captured = super.capture();
    if (captured instanceof Class) {
      this.runtimeType = captured;
    } else {
      /**
       * 非Class的泛型变量,则调用 resolveType 方法解析 T 为具体参数 
       * 由declaringClass创建的TypeToken对象完整保存了类型变量到实际类型的对应表,
       * 所以resolveType方法就是通过查表得到对应具体类型
       */
      this.runtimeType = of(declaringClass).resolveType(captured).runtimeType;
    }
  }

调用示例

java 复制代码
import static org.junit.Assert.*;

import java.lang.reflect.Type;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;

import com.google.common.reflect.TypeToken;

/**
 * Guava TypeToken 解析类型变量(TypeVariable)测试
 * @author l0km
 */
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ResolveTypeTest {

	@SuppressWarnings("serial")
	@Test
	public void test() {
		Base<String,Date> base = new Base<String,Date>() {};
		assertEquals(String.class, base.inputType);
		assertEquals(Date.class, base.outputType);

		Sub1<Date> sub1 = new Sub1<Date>() {};
		assertEquals(String.class, sub1.inputType);
		assertEquals(Date.class, sub1.outputType);
		
		Sub2<Map<Integer,Type>> sub2 = new Sub2<Map<Integer,Type>>() {};
		assertEquals(new TypeToken<Map<Integer,Type>>() {}.getType(), sub2.inputType);
		assertEquals(String.class, sub2.outputType);
		
		Sub3<List<Date>> sub3 = new Sub3<List<Date>>() {};
		assertEquals(String.class, sub3.inputType);
		assertEquals(new TypeToken<List<Date>>() {}.getType(), sub3.outputType);

		Sub4<int[]> sub4 = new Sub4<int[]>() {};
		assertEquals(int[].class, sub4.inputType);
		assertEquals(String.class, sub4.outputType);
	}

	public static abstract class Base<F,T>{
		final Type inputType;
		final Type outputType;
		@SuppressWarnings("serial")
		protected Base(){
			inputType = new TypeToken<F>(getClass()) {}.getType();
			System.out.printf("inputType: %s\n",inputType);
			outputType = new TypeToken<T>(getClass()) {}.getType();
			System.out.printf("outputType: %s\n",outputType);
		}
	}
	public static abstract class Sub1<T> extends Base<String,T>{
	}
	public static abstract class Sub2<F> extends Base<F,String>{
	}
	public static abstract class Sub3<T> extends Sub1<T>{
	}
	public static abstract class Sub4<F> extends Sub2<F>{
	}

}
相关推荐
程序员张317 分钟前
Maven编译和打包插件
java·spring boot·maven
ybq195133454311 小时前
Redis-主从复制-分布式系统
java·数据库·redis
weixin_472339462 小时前
高效处理大体积Excel文件的Java技术方案解析
java·开发语言·excel
小毛驴8502 小时前
Linux 后台启动java jar 程序 nohup java -jar
java·linux·jar
DKPT3 小时前
Java桥接模式实现方式与测试方法
java·笔记·学习·设计模式·桥接模式
好奇的菜鸟4 小时前
如何在IntelliJ IDEA中设置数据库连接全局共享
java·数据库·intellij-idea
DuelCode5 小时前
Windows VMWare Centos Docker部署Springboot 应用实现文件上传返回文件http链接
java·spring boot·mysql·nginx·docker·centos·mybatis
优创学社25 小时前
基于springboot的社区生鲜团购系统
java·spring boot·后端
幽络源小助理5 小时前
SpringBoot基于Mysql的商业辅助决策系统设计与实现
java·vue.js·spring boot·后端·mysql·spring
猴哥源码5 小时前
基于Java+springboot 的车险理赔信息管理系统
java·spring boot