Сложный вопрос, на который я близок, чтобы оставить надежду. Я пытаюсь сделать
функция, но у меня проблемы с получением ArrayList.toArray()
для возврата типа, который я хочу.
Вот минимальный пример, который демонстрирует мою проблему:
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();
}
Обычно я мог бы использовать форму (T[]) list.toArray(new T[0])
, но есть две дополнительные трудности:
- Из-за ковариационных правил я не могу типизировать массивы,
(T[]) myObjectArray
дает ClassCastException
- Вы не можете создать новый экземпляр универсального типа, то есть я не могу создать экземпляр
new T[]
. Также я не могу использовать клон на одном из элементов ArrayList
или пытаться получить его класс.
Я пытался получить некоторую информацию, используя следующий вызов:
public static void main(String[] args) {
System.out.println(test("onestring", "twostrings"));
}
результат имеет вид [Ljava.lang.Object;@3e25a5
, свидетельствующий о том, что приведение типа при возврате неэффективно. странно следующее:
public static void main(String[] args) {
System.out.println(test("onestring", "twostrings").getClass());
}
возвращается с:
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
at patchLinker.Utilities.main(Utilities.java:286)
Так что я думаю, что он думает, что это метка массива String, но внутренне это массив объектов, и любые попытки получить доступ выявляют это несоответствие.
Если кто-нибудь сможет найти способ обойти это (так как два нормальных обходных пути мне запрещены), я был бы очень признателен.
K.Barad
JDK1.6
Редактировать
Спасибо Питеру Лоури за решение начальной проблемы. Теперь вопрос в том, как применить решение к моему менее тривиальному примеру:
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);
}
Результат на данный момент
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)
Я все еще делаю некоторые тесты, чтобы увидеть, могу ли я получить более полезную информацию, чем эта, но в данный момент я не уверен, с чего начать. Я добавлю больше информации, которую получу, когда получу.
K.Barad
редактировать 2
Теперь еще немного информации. Я попытался собрать массив вручную и передать элементы поэлементно, поэтому я бы использовал типизацию как T, а не T []. Я нашел интересный результат:
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;
}
}
Я все еще получаю следующий вывод:
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)
Означает ли это, что вы не можете писать в T[]
, даже если вам удастся создать его косвенно?