java - 无法从 Class 对象中获取 Type 标记?
问题描述
假设我有一个由各种类实现的通用接口。
public interface MyInterface<K, V> {
// Some method declarations
// ...
// But owing to Java type erasure, we also have...
Class<K> getKClass();
Class<V> getVClass();
}
现在,我使用对象存储来获取实现MyInterface
. 而且我在编写代码时不知道参数的类型K
和V
. 但是,可以访问Class
预先存储的相应对象。现在我可以在请求工厂时使用它们。
public MyInterface getObjectFromStore(String uniqueKey,
Class kClazz, Class vClazz) {
MyInterface concreteInstance = MyClassWarehouse.retrieveObject(uniqueKey);
// Perform type checks.
boolean kMismatch = !kClazz.isAssignableFrom(concreteInstance.getKClass());
boolean vMismatch = ...;
// Mismatch handling...
...
// Everything's okay
return concreteInstance;
}
在我看来,如果我可以将我的方法编写为:
public <K, V> MyInterface<K, V> getObjectFromStore(String uniqueKey) {
try {
MyInterface<K, V> concreteInstance = MyClassWarehouse.retrieveObject(uniqueKey);
return concreteInstance;
} catch (ClassCastException cce) {
// Better way to handle type mismatch
...
}
}
但这要求我在编写代码时知道这些类。
MyInterface<String, Double> retrievedObject = getObjectFromStore("key123");
因为我只有类对象,所以我必须使用第一种“笨拙”的方法。尤其是:
// Must use this...
MyInterface retrievedObject = getObjectFromStore("key123", kClazz, vClazz);
// ... because this (or anything equivalent) is not possible.
MyInterface<kClazz, vClazz> retrievedObject = getObjectFromStore("key123");
在我看来,由于类型在 Java 中不是真正的对象,因此无法从类对象中获取类型标记K
和以启用第二种方法的方式。但是,语法糖会很好。V
kClazz
vClazz
是否还有其他原因无法启用此功能?
解决方案
如果您放弃编译时检查以支持运行时检查,那么您将需要来自两个来源的运行时类型对象才能进行任何比较。
所以,是的,最简单的就是Class
在两端指定对象。在简单的情况下。
<T> void put(Class<T> t, T object);
<T> T get(Class<T> t);
添加特定的双参数化类型(Java 中没有更高类型的类型)、两种类型和一个键(对字符串编程的嘘声)。
<K,V> void put(Class<K> k, Class<V> v, Key key, My<K,V> object);
<K,V> My<K,V> get(Class<K> k, Class<V> v, Key key);
有机会将三个关键对象合二为一。
public final class MyKey<K,V> {
public static of(Class<K> k, Class<V> v, SimpleKey key) {
....
}
...
}
<K,V> void put(MyKey<K,V> key, My<K,V> object);
<K,V> My<K,V> get(MyKey<K,V> key);
或者,您可以寻找不同的类对象来源。它们可从方法签名中获得。
public interface MyReceiver<K,V> {
void accept(My<K,V> object);
}
/** @param receiver Runtime type should specialise type parameters. */
void get(MyReceiver<?,?> receiver);
(MyReciever<?,?>
可能是一个标准Consumer<? extends MyReciever<?,?>>
。)
您可以添加一个额外的简单键作为参数get
(对 lambda 友好)、方法 on MyReceiver
、注释 on accept
or MyReceiver
,或者从中删除方法MyReceiver
并使用它们运行时类型使用的任何方法名称(也许注释以查找您使用的方法)想)。
事实上,这种在接口中指定所需类型的方法比老式的异构映射更现代。
(另请注意,“存储库”是您的仓库的标准术语。)
推荐阅读
- mongoose - 猫鼬:无法从数组中删除项目
- python - 'wordItem' 对象没有属性 'len',django,python
- swagger - Swagger Open API 自定义标头
- python - 使用 excel2json 转换为 JSON - 日期问题
- javascript - 错误处理程序不和谐
- python - df.quantile(axis = 1) 抛出 NaN
- reactjs - 在单独的函数中使用默认值反应渲染输入以显示错误
- mongodb - 节点应用程序无法连接到我的 ubuntu 实例上的 mongo 映像
- python - 有没有办法用曲线边缘绘制网络图?
- elixir - 将变量分配给 case 语句的返回 Elixir