从几天前开始,我开始从事Web服务项目。该项目使用 Jackson 来编组和解组 JSON对象。所以我的问题是:
为什么在创建{}
实例时总是必须放置TypeReference
?我知道构造函数是protected
,但是为什么是protected
?我认为这就像黑客一样,因为TypeReference
是abstract
,您可以做到这一点,从而使构造函数可见并创建该构造函数的实现。但是,这有什么意义呢?
String jsonString = "{\" firstName\":\"John\",\"lastName\":\"Chen\"}";
ObjectMapper objectMapper = new ObjectMapper();
// properties will store name and value pairs read from jsonString
Map<String, String> properties = objectMapper.readvalue(
jsonString, new TypeReference<Map<String, String>>()
{ //
});
最佳答案
TL; DR
通过子类化,TypeReference
可以提取实际的泛型类型参数。例如:
TypeReference<String> ref = new TypeReference<String>(){};
System.out.println(ref.getType());
印刷品:class java.lang.String
当您不能使用普通类时,这可能会很有用。例如,当这不起作用时:// doesn't work
Type type = ArrayList<String>.class;
您仍然可以使用TypeReference
获得该类:// will yield Class<ArrayList<String>>>
Type type = new TypeReference<ArrayList<String>>(){}.getType();
详细
查看source code of
TypeReference
(using Jackson 2.8.5)时,您可以看到构造函数主体包含以下几行:Type superClass = getClass().getGenericSuperclass();
if (superClass instanceof Class<?>) { // sanity check, should never happen
throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information");
}
_type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
有趣的行是第一行和最后一行。让我们仔细看看第一行:Type superClass = getClass().getGenericSuperclass();
例如,当您使用匿名类创建子类时:TypeReference<SomeStype> ref = new TypeReference<SomeType>(){};
然后getClass
返回当前的Class
对象(一个匿名类),并且getGenericSuperclass()
从当前实现的扩展源Class
返回class
对象,在本例中,superClass
将等于Class<TypeReference<?>>
。现在,当查看构造函数主体的最后一行时:
_type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
我们知道superClass
是Class
的TypeReference<?>
对象,我们知道它具有通用参数。因此,将其强制转换为ParameterizedType
。此指定的Type
具有getActualyTypeArguments()
方法,该方法返回该类指定的所有通用参数的数组。在我们的例子中只有1。因此[0]
将产生第一个元素。在示例中,我们将获得实际指定的类型参数SomeType
。