我正在尝试在我的 Java 代码中获取泛型类型的类<T>。我正在使用阿里巴巴的 FastJSON 进行 JSON 处理。以下是我的代码的关键部分:

呼叫者:

public Features findFeatureById(BigDecimal id) {
    return mixedCacheService.get(FEATURE, id.toString(), new MixedCacheService.Func<>(() -> featuresDao.selectById(id)));
}

被调用者:

public <T> T get(@NotNull CacheBaseConstants cacheBaseConstants, @NotNull String key, @NotNull Supplier<T> getter) {
    String value = get(cacheBaseConstants, key);
    if ("".equals(value)) {
        return null;
    }
    // How can I get T.class here?
    return Optional.ofNullable(value)
            .map(o -> JSON.parseObject(value, T.class))
            .orElseGet(() -> put(cacheBaseConstants, key, getter));
}

我尝试扩展com.alibaba.fastjson.TypeReference

public static class Func<T> extends TypeReference<T> {
    private Supplier<T> supplier;

    public Func(Supplier<T> supplier) {
        super();
        this.supplier = supplier;
    }

    public T get() {
        return supplier.get();
    }
}

我也尝试使用getter.supplier.getClass().getGenericSuperclass(),但它又回来了Object


处方

import cn.hutool.core.lang.TypeReference;

import java.util.function.Supplier;

public abstract class SupplierProxy<T> extends TypeReference<T> {
    private final Supplier<T> supplier;

    public SupplierProxy(Supplier<T> supplier) {
        super();
        this.supplier = supplier;
    }

    public T get() {
        return supplier.get();
    }

}

单元测试

   @Test
    public void get() {
        Features actual = new Features();
        actual.setName("123");
        assertEquals(actual,mixedCacheService.get(FEATURE_BY_KEY, "1", new SupplierProxy<Features>(() -> actual) {
        }));
        assertEquals( actual,mixedCacheService.get(FEATURE_BY_KEY, "1", new SupplierProxy<Features>(() -> actual) {
        }));
    }

谢谢大家的回复,它们给了我启发

1

  • 3
    你不能。这就是“擦除”的意思。泛型是编译器想象出来的。如果在编译时不可能知道,那么就不可能知道


    – 


最佳答案
1

你不能。这就是“擦除”的意思。泛型是编译器想象出来的。如果在编译时不可能知道,那么就不可能知道。

泛型在签名中保留。换句话说,给定:

class Foo<K, T extends List<K>> {}

然后,在运行时你仍然可以获取泛型,但你可以获取的是编译时存在的内容。换句话说,你可以从字面上获取:

  • 字母“K”
  • 字母“T”
  • T 延伸的事实List<K>

你所不能得到的,是给予的,说:

Foo<String, ArrayList<String>> x = new Foo<>();
System.out.println(deriveStatsFrom(x));

deriveStatsFrom不可能获得String或在这里。ArrayList<String>不是“很难”的问题;不,这是不可能的问题——编译器会删除所有这些东西,因此在运行时根本不可能确定这一点。

你提到了com.alibaba.fastjson.TypeReference

此类专门设计用于解决这个问题

要使用它,您必须像这样编写类型引用:

TypeReference<List<String>> stringListRef = new TypeReference<List<String>>() {};

{}注意结尾处的奇怪之处。这是强制性的。这会创建一个很小的类,类确实带有其签名的泛型。换句话说,上面的内容有很多语法糖:

class SomeIrrelevantName extends TypeReference<List<String>> {}

TypeReference<List<String>> stringListRef = new SomeIrrelevantName();

因此,stringListRef.getClass()让您得到它。

这就是 API 希望你做的事情。在你的方法中,你必须添加一个类型为 的参数TypeReference<T>;你粘贴的这个方法无法知道,所以你无法绕过它。你真的必须不断地告诉自己这句话:如果在编译时你不知道,那么你就不知道。在编译时知道它的东西必须制作这个东西并传递它。

4

  • 如果T没有嵌套泛型,也可以传递Class<T>而不是TypeReferece<T>。这更容易读写 – 我MyObject.class更喜欢new TypeReference<MyObject> {}一周中的任何一天。


    – 

  • Class<T>是个坏主意。这是一个双向谎言。它不能表示任意的 T – 通常需要接受 typeref 的代码不知道要接受的类型引用是否不含泛型,并且Class<T>不能表示任何包含泛型的类型。但是,更糟糕的是 –j.l.Class 可以表示原语;int.class是一个东西。但泛型不能。换句话说,这是一个坏主意。Class<T>作为参数对我来说在代码审查中几乎是自动否决。总会有更好的答案。在极少数情况下,它是像这里这样的超类型标记。在大多数情况下,是工厂。


    – 


  • 我想传入一个lambda函数作为参数,以lambda的返回值参数作为序列化的类型,并且可以少传递一个Class参数。


    – 

  • @finger 这是不可能的。


    –