Class.java为什么不提供`Type getType()`和`Type getGenericType()`这样的方法?

huangapple go评论60阅读模式
英文:

Why Class.java don't provide methods like `Type getType()` and `Type getGenericType()`?

问题

为什么我必须定义一个子类来获取父类的泛型参数的Type?这个限制是必要的吗?

我阅读了阿里巴巴的Fastjson代码,试图弄清楚为什么必须使用TypeReference来创建一个匿名子类。然后我发现,即使是自己的Type,一个对象也不能获取自己的泛型参数Type

public class TypeReference {
    static ConcurrentMap<Type, Type> classTypeCache
            = new ConcurrentHashMap<Type, Type>(16, 0.75f, 1);

    protected final Type type;

    protected TypeReference() {
        Type superClass = getClass().getGenericSuperclass();

        Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0];

        Type cachedType = classTypeCache.get(type);
        if (cachedType is null) {
            classTypeCache.putIfAbsent(type, type);
            cachedType = classTypeCache.get(type);
        }

        this.type = cachedType;
    }
    // ...
}

抱歉我的英语不太好。感谢你的回答。

英文:

Why I have to define a subclass to get the Type of superclass' generic param? Is the limit necessary?

I read the code of Fastjson of Alibaba and tried to figure out why use TypeReference must create an anonymous subclass. Then I found that an object cannot get its own generic param Type even its own Type.

public class TypeReference {
    static ConcurrentMap&lt;Type, Type&gt; classTypeCache
            = new ConcurrentHashMap&lt;Type, Type&gt;(16, 0.75f, 1);

    protected final Type type;

    protected TypeReference() {
        Type superClass = getClass().getGenericSuperclass();

        Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0];

        Type cachedType = classTypeCache.get(type);
        if (cachedType == null) {
            classTypeCache.putIfAbsent(type, type);
            cachedType = classTypeCache.get(type);
        }

        this.type = cachedType;
    }
    // ...
}

Sorry for my poor English. Thanks for your answers.

答案1

得分: 2

因为类型擦除

考虑以下示例

List<String> stringList = new ArrayList<>();
List<Number> numberList = new ArrayList<>();

System.out.println(stringList.getClass() == numberList.getClass());

这会打印 true。无论泛型类型如何,ArrayList 的这两个实例都具有相同的类和一个单一的 Class 对象。那么如何让这个单一的 Class 对象为两个对象返回正确的 类型 呢?

我们甚至可以再进一步,

List<String> stringList = Collections.emptyList();
List<Number> numberList = Collections.emptyList();

System.out.println(stringList == (Object)numberList);

对象不知道它们的泛型类型。如果一个集合是不可变的并且始终为空,它可以用来表示任意空列表。对于无状态函数也是一样的

Function<String, String> stringFunction = Function.identity();
Function<Number, Number> numberFunction = Function.identity();

System.out.println(stringFunction == (Object)numberFunction);

打印 true(在大多数系统上;这不是一种保证的行为)。

泛型类型只在某些特定情况下保留,比如字段和方法声明以及泛型超类型的签名。

这就是为什么你需要创建一个子类来利用它将存储声明的泛型超类型的事实。虽然有时候以更简单的方式构造一个 类型 实例会很有用,适当的工厂方法可以被视为一个缺失的特性,但通常情况下无法获取任意对象(或其 Class)的实际泛型类型。

英文:

Because of Type Erasure.

Consider the following example

List&lt;String&gt; stringList = new ArrayList&lt;&gt;();
List&lt;Number&gt; numberList = new ArrayList&lt;&gt;();

System.out.println(stringList.getClass() == numberList.getClass());

This will print true. Regardless of the generic type, both instances of ArrayList have the same class and a single Class object. So how could this single Class object return the right Type for both objects?

We can even get a step further,

List&lt;String&gt; stringList = Collections.emptyList();
List&lt;Number&gt; numberList = Collections.emptyList();

System.out.println(stringList == (Object)numberList);

Objects do not know their generic type. If a collection is immutable and always empty, it can be used to represent arbitrary empty lists. The same applies to stateless functions

Function&lt;String, String&gt; stringFunction = Function.identity();
Function&lt;Number, Number&gt; numberFunction = Function.identity();

System.out.println(stringFunction == (Object)numberFunction);

Prints true (on most systems; this is not a guaranteed behavior).

Generic types are only retained in some specific cases, like the signatures of field and method declarations and generic super types.

That’s why you need to create a subclass to exploit the fact that it will store the declared generic supertype. While it sometimes would be useful to construct a Type instance in a simpler way and a suitable factory method can be regarded a missing feature, getting the actual generic type of an arbitrary object (or its Class) is not possible in general.

huangapple
  • 本文由 发表于 2023年2月19日 14:43:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/75498438.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定