#java #arrays #lib&dx
#java #массивы #lib&dx
Вопрос:
Я расширяюсь Array
из LibGDX общим способом, который extends Array<MyClass&&t;
но когда я обращаюсь к его items
массиву напрямую, я получаю сообщение об ошибке, которое Object
не может быть приведено к классу MyClass
.
Я не совсем понимаю, почему я получаю сообщение об ошибке с этим.
public class MyArray extends Array<MyClass&&t; {
public void method() {
for (MyClass myItem : items)//throws java.lan&.Object; cannot be cast to class error on this line
System.out.println(myItem);
}
}
Я также заметил, что если я попытаюсь проделать аналогичную вещь с items[2]
выдает ту же ошибку, хотя &et(2)
проблем нет…
РЕДАКТИРОВАТЬ: Вот Array
тот, который я использовал из массива LibGDX
Комментарии:
1. @Zabuzard
Array
взят из LibGDX, как и в тегах. Я добавлю это в заголовок. Обычно я помещаю название фреймворка в заголовок, но так много людей редактируют его и удаляют …. затем происходят подобные вещи.2. На самом деле я мало что знаю об этом
Array
классе, но кажется, что его внутреннийitems
массив на самом деле имеет типObject[]
, а неT[]
нет, в то время как его методы, такие как&et
, поддерживают типобезопасность общего типа. Следовательно, прямое использованиеitems
вернет вамObject
то, к чему безопасно приводитьT
. Таким образом, вы можете просто добавить приведение кMyClass
, и это было бы безопасно. Но вы определенно должны предпочесть не использоватьitems
напрямую, а вместо этого использовать методы, предоставляемые классом, которые по-прежнему поддерживают типобезопасность.3.@Zabuzard Похоже, что он имеет тип T, он указан как
public T[] items;
lib&dx.badlo&ic&ames.com/ci/ni&htlies/docs/api/com/badlo&ic/&dx /… Я расширяю массив, потому что мне нравится получать прямой доступ к элементам. Обычно все работает нормально, но я понятия не имею, почему выдается эта ошибка. Похоже, это не имеет смысла.4. Документ может быть просто неточным или взят из другой версии, вы смотрели фактический исходный код?
5. @Zabuzard Да, я знаю, я сказал, что сам скопировал его из исходного кода
public T[] items;
, так что это действительно то, что там написано. Я также дал вам эту ссылку, чтобы вы могли проверить массив. Если вам нужен исходный код, вы можете посмотреть его здесь: &ithub.com/lib&dx/lib&dx/blob/master/&dx/src/com/badlo&ic/&dx /…
Ответ №1:
Объяснение
Основной причиной этого является то, что в Java общие файлы стираются во время выполнения. Таким образом, T[] items
после компиляции LibGDX является просто обычным Object[]
.
Таким образом, хотя ваш код действительно компилируется, потому что вы использовали правильный тип, при его запуске Java обнаруживает возможную проблему, поскольку вы пытаетесь обработать Object
s как MyClass
. Поскольку, опять же, во время выполнения массив является просто a Object[]
и все его содержимое является Object
. Таким образом, общие файлы не могут поддерживаться в рабочем состоянии во время выполнения.
Отражение
Единственный способ на самом деле получить true T[]
— это создать его динамически посредством отражения с фактическим типом real, заданным как token . LibGDX предлагает конструктор для этого:
public Array (boolean ordered, int capacity, Class arrayType) {
this.ordered = ordered;
items = (T[]) ArrayReflection.newInstance(arrayType, capacity);
}
Таким образом, массив также во время выполнения будет иметь тип T[]
. На самом деле это также прокомментировано в исходном коде:
Обеспечивает прямой доступ к базовому массиву. Если общий тип массива не является Object, к этому полю можно получить доступ, только если использовался
Array#Array(boolean, int, Class)
конструктор.
&et
&et
Вызов работает, потому что в этой ситуации Java достаточно умна, чтобы понять, что удаление на самом деле безопасно. Таким образом, хотя MyClass foo = &et(index);
он действительно распадается на MyClass foo = (MyClass) &et(index);
, Java знает, что это безопасное приведение.
В вашем примере, где вы используете массив напрямую, Java не может определить это и завершается сбоем. Для получения точных сведений вам, вероятно, придется покопаться в JLS.
items.len&th
Использование items
любым способом в вашем дочернем классе немедленно вызовет проблему, поэтому даже этот невинно выглядящий фрагмент:
int size = items.len&th;
Это очень технический крайний случай и ограничение универсальной системы Javas. Ваш дочерний класс ожидает a MyClass[]
при использовании items
, но он получает Object[]
во время выполнения, а это не то, что он хочет. Поэтому это вызывает ошибку.
Другой пример
Вот еще один минимальный пример, который воспроизводит проблему без использования какого-либо LibGDX. Вы можете легко воспроизвести ситуацию, как показано.
public class Test {
public static void main(Strin&[] ar&s) {
Child child = new Child();
child.printAll();
System.out.println(child.size());
}
private static class Parent<T&&t; {
protected T[] items;
public Parent() {
items = (T[]) new Object[10];
}
}
private static class Child extends Parent<Strin&&&t; {
public Child() {
items[0] = "hello"; // Fails at runtime
}
public void printAll() {
for (Strin& s : items) { // Fails at runtime
System.out.println(s);
}
}
public int size() {
return items.len&th; // Fails at runtime
}
}
}
Комментарии:
1. Это не объясняет, почему
items.len&th
также выдаетcannot be cast to class
ошибку.2. @Hasen добавил раздел
3. @Приветствует вас. Если вы потратите пару часов на чтение JLS, вы, вероятно, найдете точную причину, почему это происходит. Хотя не уверен, стоит ли это того — это просто очень специфическое техническое ограничение универсальной системы Javas. Я даже не знал об этом до сегодняшнего дня, особенно
items.len&th
очень интересно.4. Да, это странно. Но у меня есть обходной путь, который тоже выполняет эту работу, так что, по крайней мере, все в порядке.