从几天前开始,我开始从事Web服务项目。该项目使用 Jackson 来编组和解组 JSON对象。所以我的问题是:

为什么在创建{}实例时总是必须放置TypeReference?我知道构造函数是protected,但是为什么是protected?我认为这就像黑客一样,因为TypeReferenceabstract,您可以做到这一点,从而使构造函数可见并创建该构造函数的实现。但是,这有什么意义呢?

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];
我们知道superClassClassTypeReference<?>对象,我们知道它具有通用参数。因此,将其强制转换为ParameterizedType。此指定的Type具有getActualyTypeArguments()方法,该方法返回该类指定的所有通用参数的数组。在我们的例子中只有1。因此[0]将产生第一个元素。在示例中,我们将获得实际指定的类型参数SomeType

10-04 17:12