我正在尝试在我的 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
最佳答案
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 这是不可能的。
–
|
–
|