【发布时间】:2014-03-17 16:05:32
【问题描述】:
我用来将重复对象的列表/数组存储为映射,其中键是对象本身,值是它的多重性。
说['d', 'a', 'd', 'd', 'y'] --> {d=3, a=1, y=1}(订单被保留,FWIW)
我这样做既是为了节省字节,也是因为操纵这张计数图让我的生活更轻松
有时我确实需要恢复为列表/数组形式,
说{d=3, a=1, y=1} --> ['d', 'd', 'd', 'a', 'y']
显然无法重新创建原始订单,该信息已丢失,但这无关紧要,因为我认为等效的两个列表/数组 如果它们具有相同的大小并共享完全相同的元素(包括相对多重性)
为了从地图到列表,我编写了以下方法:
<T> ArrayList<T> counted2Lst(final LinkedHashMap<T, Integer> map){
final ArrayList<T> grp=new ArrayList<T>(map.size()); // larger most of the times
for (final Entry<T, Integer> entry : map.entrySet()) {
final T obj=entry.getKey();
for(int i=entry.getValue(); i>0; i--){
grp.add(obj);
}
}
return grp;
}
预期会做什么:从 Map 中构建一个 ArrayList
当我决定做同样的事情时遇到了问题,但得到的是 T[](不是 Object[])而不是 ArrayList
这是我的第一次尝试:
<T> T[] counted2Arry(final Map<T, Integer> map){
final ArrayList<T> tmpLst=counted2Lst(map); // method defined above
@SuppressWarnings("unchecked")
T[] arryT=(T[]) java.lang.reflect.Array.newInstance(tmpLst.get(0).getClass(), tmpLst.size());
return tmpLst.toArray(arryT);
}
据我所知,由于类型擦除,在运行时无法获取 Collection/Map 的参数化类型, 所以要实际创建一个 T 数组,我必须首先获取存储在 tmpLst 中的第一个对象的类(被授予 T 类型) 然后通过 java.lang.reflect.Array.newInstance() 制作一个 T 数组
问题是如果输入映射是空的(这是完全合理和合法的情况),那么就没有对象可以检测到 T 的实际类。
换句话说,我用Java怎么说?
if(map.size()==0) { // or (tmpLst.size()==0)
// return a zero-sized T[0] (as opposed to a zero-sized Object[])
}
【问题讨论】:
-
顺便看看
toArray方法在java集合中是如何实现的。大多数情况下,它只是将Object[]转换为T[],因为类型擦除以及除了Ts 之外什么都不会放在数组中的事实。 -
出于某种原因需要数组吗?数组不能与泛型很好地混合。返回列表总是更方便。客户可以根据需要拨打
toArray。 -
counted2Lst() 确实返回了一个 List
,但我想允许作为选项返回一个 T[](这就是 counted2Arry() 试图做的)。 -
... continue ... List.toArry() 确实返回 Object[] - 而不是 T[] - List.toArry(T[]) 需要指定数组类型,其中是我试图解决的信息(客户端程序员可能不知道该信息)。事实上,经过几天的调查,我得出的结论是,我的尝试真的很天真,目前 Java 不允许做我想做的事,主要是因为类型擦除;我不知道 Java 8(可能会破坏兼容性)是否允许这样做。
标签: java arrays generics reflection