Java从另一个数组的通用运行时类型创建数组
我有下面的代码,它合并了两个数组,并且应该处理除原语之外的任何类型Java从另一个数组的通用运行时类型创建数组,java,arrays,generics,Java,Arrays,Generics,我有下面的代码,它合并了两个数组,并且应该处理除原语之外的任何类型 @SuppressWarnings("unchecked") public static synchronized <E> E[] aryMergeNoDup(E[]... arys){ HashSet<E> hs = new HashSet<E>(); for(E[] ary : arys) { if(ary == null) continu
@SuppressWarnings("unchecked")
public static synchronized <E> E[] aryMergeNoDup(E[]... arys){
HashSet<E> hs = new HashSet<E>();
for(E[] ary : arys) {
if(ary == null) continue;
for(E item : ary) {
if(item != null) hs.add(item);
}
}
hs.remove(null);
return hs.toArray((E[]) Array.newInstance(
arys.getClass().getComponentType(),hs.size()));
}
变量arys
的运行时类型为String[];但是,当我用String.class
替换arys.getClass().getComponentType()
时,代码运行良好
但是,该方法只能用于字符串,因为这样做。我看不出哪里出了问题,因为它们都应该引用java.lang.String
AbstractCollection.java:188中引发异常的行是:
r[i] = (T)it.next();
public <T> T[] toArray(T[] a) {
// Estimate size of array; be prepared to see more or fewer elements
int size = size();
T[] r = a.length >= size ? a :
(T[])java.lang.reflect.Array
.newInstance(a.getClass().getComponentType(), size);
Iterator<E> it = iterator();
for (int i = 0; i < r.length; i++) {
if (! it.hasNext()) { // fewer elements than expected
if (a != r)
return Arrays.copyOf(r, i);
r[i] = null; // null-terminate
return r;
}
r[i] = (T)it.next();
}
return it.hasNext() ? finishToArray(r, it) : r;
}
r[i]=(T)it.next();
公共T[]toArray(T[]a){
//估计数组的大小;准备查看更多或更少的元素
int size=size();
T[]r=a.长度>=尺寸?a:
(T[])java.lang.reflect.Array
.newInstance(a.getClass().getComponentType(),大小);
迭代器it=迭代器();
对于(int i=0;i
我认为问题在于arys
类似于数组的数组。因此,可能arys.getClass().getComponentType()
是String[]
,而不是String
,arys
的运行时类型是E[]
,而不是E[]
。因此,您可能需要arys.getClass().getComponentType().getComponentType()
作为Array.newInstance
的参数,这里有两个独立的东西在交互。首先,您使用的是varargs,它将其参数封装在动态生成的数组中。所以ARY的类型将是E[]],所以get组件的类型将是E[]。其次,泛型意味着E在运行时被擦除为Object,所以即使是两个getComponentType
调用也不会将其删除,除非您对始终返回Object[]没有异议
您可以做的是使用arys[0]的组件类型(如果存在)。这甚至不适用于所有情况,因为例如,第二个数组的类型可能是超类,或者是第一个赋值的同级,与第一个类型的数组不兼容
为了解决这个问题,您可以通过检查所有数组的类型来计算最小上界类型,但是我认为如果您的典型用法是相同类型的数组,那么与“第一种类型赢”相比,这是过分的 arys.getClass().getComponentType().getComponentType()很管用!“其次,泛型意味着E在运行时被擦除为对象,所以即使两个getComponentType调用也不会删除它——除非您同意始终返回Object[]”。这没有意义。
arys
的类型是E[][]
,这意味着arys
的运行时类型,如果不是null
,则保证是E[][]
或子类型,除非您在某个地方做了不安全的事情。当然。我说的是“E
在运行时被擦除为Object
”,而不是“E[][/code>在运行时被擦除为Object
”。要点是,您将无法使用arys.getComponentType().getComponentType()
来确定E的类型,而不是传递数组的运行时类型。确定,您是对的-varargs数组的运行时类型似乎是根据所传递对象的编译时类型选择的-我原以为它将始终是Object[]。因此getComponentType().getComponentType()
将反映编译时的选择。当调用站点上的数组的编译时类型不等于其最派生的运行时类型时,使用元素的类型仍将选择更具体的数组类型。
r[i] = (T)it.next();
public <T> T[] toArray(T[] a) {
// Estimate size of array; be prepared to see more or fewer elements
int size = size();
T[] r = a.length >= size ? a :
(T[])java.lang.reflect.Array
.newInstance(a.getClass().getComponentType(), size);
Iterator<E> it = iterator();
for (int i = 0; i < r.length; i++) {
if (! it.hasNext()) { // fewer elements than expected
if (a != r)
return Arrays.copyOf(r, i);
r[i] = null; // null-terminate
return r;
}
r[i] = (T)it.next();
}
return it.hasNext() ? finishToArray(r, it) : r;
}