A difficult question which I'm close to giving up all hope on. I'm trying to make a
function, but am having problems getting ArrayList.toArray()
to return the type I want.
Here's the minimal example that demonstrates my problem:
public static <T> T[] test(T one, T two) {
java.util.List<T> list = new ArrayList<T>();
list.add(one);
list.add(two);
return (T[]) list.toArray();
}
Normally I'd be able to use the form (T[]) list.toArray(new T[0])
but there are two added difficulties:
- Because of the covariance rules I cannot typecast arrays,
(T[]) myObjectArray
gives aClassCastException
- You cannot create a new instance of a generic type, meaning I cannot instance
new T[]
. Nor can I use clone on one of the elements ofArrayList
or try to get its class.
I've been trying to get some information using the following call:
public static void main(String[] args) {
System.out.println(test("onestring", "twostrings"));
}
the result is of the form [Ljava.lang.Object;@3e25a5
suggesting that the typecast on the return is not effective. strangely the following:
public static void main(String[] args) {
System.out.println(test("onestring", "twostrings").getClass());
}
comes back with:
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
at patchLinker.Utilities.main(Utilities.java:286)
So my best guess is that it think's it's a String array label wise, but internally is an Object array, and any attempts to access brings that inconsistancy out.
If anyone can find any way of working around this (since the two normal workarounds are denied to me) I'd be very greatful.
K.Barad JDK1.6
Edit
Thanks to Peter Lawrey for solving the initial problem. Now the issue is how to make the solution apply to my less trivial example:
public static <T> T[] unTreeArray(T[][] input) {
java.util.List<T> outList = new ArrayList<T>();
java.util.List<T> tempList;
T[] typeVar;
for (T[] subArray : input) {
tempList = java.util.Arrays.asList(subArray);
outList.addAll(tempList);
}
if (input.length > 0) {
typeVar = input[0];
} else {
return null;
}
return (T[]) outList.toArray((T[]) java.lang.reflect.Array.newInstance(typeVar.getClass(),outList.size()));
}
public static void main(String[] args) {
String[][] lines = { { "111", "122", "133" }, { "211", "222", "233" } };
unTreeArray(lines);
}
The result at the moment is
Exception in thread "main" java.lang.ArrayStoreException
at java.lang.System.arraycopy(Native Method)
at java.util.ArrayList.toArray(Unknown Source)
at patchLinker.Utilities.unTreeArray(Utilities.java:159)
at patchLinker.Utilities.main(Utilities.java:301)
I'm still doing some tests to see if I can get any more useful information than this, but at the moment I'm not sure where to start. I'll add any more information I get as I get it.
K.Barad
edit 2
Some more information now. I've tried to build the array manually and transfer the items in elementwise, so I'd be typecasting as T, rather than T[]. I found an interesting result:
public static <T> T[] unTreeArray(T[][] input) {
java.util.List<T> outList = new ArrayList<T>();
java.util.List<T> tempList;
T[] outArray;
for (T[] subArray : input) {
tempList = java.util.Arrays.asList(subArray);
outList.addAll(tempList);
}
if (outList.size() == 0) {
return null;
} else {
outArray = input[0];// use as a class sampler
outArray =
(T[]) java.lang.reflect.Array.newInstance(outArray.getClass(), outList.size());
for (int i = 0; i < outList.size(); i++) {
System.out.println(i + " " + outArray.length + " " + outList.size() + " " + outList.get(i));
outArray[i] = (T) outList.get(i);
}
System.out.println(outArray.length);
return outArray;
}
}
I still get the following output:
0 6 6 111
Exception in thread "main" java.lang.ArrayStoreException: java.lang.String
at patchLinker.Utilities.unTreeArray(Utilities.java:291)
at patchLinker.Utilities.main(Utilities.java:307)
Does this mean you can't write to a T[]
even if you manage to create one indirectly?