Reputation: 113
I have the following code which merges two arrays and should handle any type apart from primitives.
@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()));
}
However when the code runs it generates this exception:
java.lang.ArrayStoreException: java.lang.String
at java.util.AbstractCollection.toArray(AbstractCollection.java:188)
at util.Utils.aryMergeNoDup(Utils.java:197)
The runtime type of the variable arys
is String[]; however, when I replace arys.getClass().getComponentType()
with String.class
the code runs fine.
However, the method can only be used for Strings because pf this. I can't see what's going wrong, as they should both refer to java.lang.String
.
The line in AbstractCollection.java:188 that throws the Exception is:
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;
}
Upvotes: 2
Views: 626
Reputation: 64895
You've got two separate things interacting here. First, you are using varargs, which under the covers wrap their arguments in an array generated on the fly. So the type of arys will be E[][], so get component type will be E[]. Second, generics mean that E is erased to Object at runtime, so even two getComponentType
calls aren't going to cut it - unless you are OK with always returning Object[].
What you could do, is use the component type of arys[0], if it exists. This won't even work for all cases, since for example the type of the second array may be a superclass, or a sibling of the first, assignment incompatible with an array of the first type.
To solve this, you could calculate the least upper bound type by examining the types of all the arrays, but I think this is overkill versus "first type wins" if your typical usage will be arrays of the same type.
Upvotes: 0
Reputation: 122364
Since it's a varargs, the runtime type of arys
will be E[][]
, not E[]
. Therefore you probably need arys.getClass().getComponentType().getComponentType()
as the argument to Array.newInstance
.
Upvotes: 3
Reputation: 11403
I believe the problem is that arys
is something like an array of arrays. So probably arys.getClass().getComponentType()
is String[]
, and not String
.
Upvotes: 0