【问题标题】:Why is Jackson TypeReference abstract?为什么 Jackson TypeReference 是抽象的?
【发布时间】:2021-09-08 13:27:59
【问题描述】:

为什么 Jackson 的 TypeReference 是抽象的?它通常使用法更难看,因为您需要包含大括号来创建内联类(并且大多数 linter 会强制您在同一行上不使用花括号)。

https://github.com/FasterXML/jackson-core/blob/master/src/main/java/com/fasterxml/jackson/core/type/TypeReference.java

new TypeReference<Map<String, String>>() {
};

这是因为一些模糊的 Java 语言限制吗?

【问题讨论】:

  • @JBNizet 回答这个问题,以便我 +1
  • @MauricePerry 我应该从一开始就这样做。现在完成。
  • 真的不同意对此的反对意见 - 它可能对那些“知情”的人有一个清晰、相当直接的答案,但通过子类化在运行时保留通用信息这一事实是这本身就是一个利基事实。

标签: java jackson


【解决方案1】:

JB Nizet 已经回答了原因。我只是想证明行动的原则。

您可以在其他课程中亲自尝试:

List<String> a = new ArrayList<String>();
List<String> b = new ArrayList<String>() {};

System.out.println(a.getClass().getGenericSuperclass());
System.out.println(b.getClass().getGenericSuperclass());

Ideone demo

输出:

java.util.AbstractList<E> 
java.util.ArrayList<java.lang.String>

如您所见,创建匿名子类会在运行时保留有关列表的具体泛型类型的类型信息。

TypeReference 的作用大致相同:

new TypeReference<Map<String, String>>() { }

有一个通用的超类:

 TypeReference<java.util.Map<java.lang.String, java.lang.String>>

从这里,你可以得到类型Map&lt;String, String&gt;。如果您为其他类型创建了类型引用:

    new TypeReference<Map<Integer, Integer>>() { };

你可以得到类型Map&lt;Integer, Integer&gt;&gt;,它与Map&lt;String, String&gt;是分开的。

如果TypeReference 不是抽象的,你可以这样写:

TypeReference<Map<String, String>> p = new TypeReference<>();
TypeReference<Map<Integer, Integer>> q = new TypeReference<>();

pq 的类型将无法区分。

【讨论】:

  • 你的第一个例子很有说明性,+1
【解决方案2】:

正是强迫你创建一个子类,因为它是捕获泛型类型的唯一方法。

它写在您链接到的 javadoc 的第一句话中:

这个泛型抽象类用于通过子类化获取完整的泛型类型信息。

(强调我的)。

该文档还包含指向解释该原则的博客文章的链接。

【讨论】:

  • 我知道需要捕获类型。我想我想了解为什么 java 会这样。
【解决方案3】:

问题本身已经得到解答,但我想提供一个解决方案,解决由于必须使用花括号并占用额外行而导致代码难看的问题。

通常是这样使用的:

Map<String, String> map = objectMapper.readValue(file, new TypeReference<>() {
});

这还不算太糟糕,但对某些人来说可能会很烦人。因此,有一种方法可以通过使用JavaType 来避免它。你可以创建一个实用方法:

private <K, V> JavaType mapType(Class<K> keyClass, Class<V> valueClass) {
    return objectMapper.getTypeFactory().constructParametricType(Map.class, keyClass, valueClass);
}

并像这样使用它:

Map<String, String> map = objectMapper.readValue(file, mapType(String.class, String.class));

列表和其他集合也可以这样做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-30
    • 1970-01-01
    相关资源
    最近更新 更多