[英]Java generic function: how to return Generic type
这是一个Java通用模式:
public <T> T getResultData(Class<T> resultClass, other_args) {
...
return resultClass.cast(T-thing);
}
典型的通话看起来像:
DoubleBuffer buffer;
buffer = thing.getResultData(DoubleBuffer.class, args);
当期望的返回类型本身是通用的时候,我从来没有弄清楚如何干净地使用这个模式。 要具体化,如果像这样的函数想要返回Map<String,String>
怎么办? 因为你无法获得泛型的类对象,当然,唯一的选择是传递Map.class
,然后你需要一个@SuppressWarning
和一个@SuppressWarning
。
一个人最终会打电话:
Map<String, String> returnedMap;
returnedMap = thing.getResultData(Map.class, some_other_args);
现在回到需要强制转换并抑制警告。
我想可以从java.lang.reflect.Type
系列而不是Class
获取一些东西,但这些并不是特别容易编造的。 看起来像:
class Dummy {
Map<String, String> field;
}
...
Type typeObject = Dummy.class.getField("field").getGenericType();
鉴于此,被调用函数可以提取基类型并将其用于转换或newInstance,但虚拟字段业务肯定看起来很难看。
请注意,这样的函数并不总是调用newInstance
。 显然,如果他们这样做,他们不需要调用resultClass.cast
。
好,。 这是一个丑陋的(部分)解决方案。 你不能一般地对通用参数进行参数化,所以你不能写
public <T<U,V>> T getResultData ...
但是你可以返回参数化集合,例如一组
public < T extends Set< U >, U > T getResultData( Class< T > resultClass, Class< U > paramClass ) throws IllegalAccessException, InstantiationException {
return resultClass.newInstance();
}
如果它存在于类签名中,你可以摆脱U-param。
是的我不认为这是可能的。
想象一下这个场景。 您有一个文件,其中包含您想要读取的序列化对象。 如果你使函数通用,你将能够在没有强制转换的情况下使用它。 但是,假设您将Map序列化为文件。
当您反序列化它时, 无法知道原始通用映射类型是什么。 就java而言,它只是一个Map
我用列表遇到了这个,这很烦人。 但我实际上最终做的是创建一个通用的“转换集合”类,它采用集合和“转换器”(可以是匿名内部类型)。
然后,当您遍历转换集合时,每个项目都会被强制转换。 这解决了警告问题。 除了警告之外,还有很多工作要做,但我不认为这是我提出这个框架的主要原因。 您还可以执行更强大的操作,例如获取文件名集合,然后编写一个转换器来加载文件中的数据,或进行查询等等。
如果要使用类型安全容器类,可以使用TypeLiteral 。 它们在Guice中用于提供类型安全绑定。 有关更多示例和TypeLiteral类,请参阅Guice源代码。
顺便说一句,如果你调用resultClass.newInstance()
,你不需要resultClass.newInstance()
。
public <T> T getResultData(Class<T> resultClass, other_args) {
...
return resultClass.newInstance();
}
所以,如果我理解你真正想要做的是(非法伪语法):
public <T, S, V> T<S, V> getResultData(Class<T<S, V>> resultClass, other_args) {
...
return resultClass.cast(T-thing);
}
你不能因为你不能进一步参数化泛型类型T
搞乱java.lang.reflect.*
会有所帮助:
Class<Map<String, String>>
这样的东西,因此无法动态创建其实例。 T<S, V>
如果你真的不需要地图的确切泛型类型,而你的代码不依赖于那种类型,但你只是对你可以编写的警告感到恼火:
Map<?, ?> returnedMap;
returnedMap = thing.getResultData(Map.class, some_other_args);
然后你可以使用任何非类型参数化的map方法,如containsKey,clear,iterator等,或迭代entrySet或将returnedMap传递给任何泛型方法,一切都是类型安全的。
Map<?, ?> returnedMap;
returnedMap = thing.getResultData(Map.class, some_other_args);
Object myKey = ...;
Object someValue = returnedMap.get(myKey);
for (Iterator<? extends Map.Entry<?,?>> it = returnedMap.entrySet().iterator(); it.hasNext(); )
if (it.next().equals(myKey))
it.remove();
for (Map.Entry<?,?> e : returnedMap.entrySet()) {
if (e.getKey().equals(myKey))
e.setValue(null); // if the map supports null values
}
doSomething(returnedMap);
...
<K,V> void doSomething(Map<K,V> map) { ... }
实际上,您可以使用类型安全的方式执行许多操作,而无需了解其键或值类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.