Я изучаю дженерики в этот период, и сегодня я нашел эту тайну для меня.Как стирание Java влияет на общие массивы?
Давайте рассмотрим следующий фиктивный класс:
public class Main{
public static void main(String[] args) {
Container<Integer> c = new Container<Integer>();
c.getArray(); //No Exception
//c.getArray().getClass(); //Exception
//int a = c.getArray().length; //Exception
}
}
class Container<T> {
T[] array;
@SuppressWarnings("unchecked")
Container() {
array = (T[])new Object[1];
}
void put(T item) {
array[0] = item;
}
T get() { return array[0]; }
T[] getArray() { return array; }
}
Из-за стирания во время выполнения, то T [] тип возвращаемого значения метода GetArray() превращается в Object [], что вполне разумно меня.
Если мы обращаемся к этому методу как к (c.getArray()), то исключаются исключения, но если мы попытаемся вызвать некоторые методы в возвращаемом массиве, например c.Array(). GetClass() или . если мы попытаемся получить доступ к полю, к примеру c.getArray() длины, то следующее исключение:
исключение в потоке «основного» java.lang.ClassCastException: [Ljava.lang. Объект; не может быть применено к [Ljava.lang.Integer;
Почему это исключение выбрасывается? Почему он не выбрасывается также для простого вызова c.getArray()? Почему он пытается использовать Integer [], если мы просто вызываем getClass() или получаем длину? Получают ли getClass() и длину не для Object []?
Заранее благодарен за ваши многочисленные (надеюсь) и объяснительные (я надеюсь, что это тоже) ответы.
Чтобы разыменовать значение 'c.getArray()', ссылка на него должна быть временно сохранена в стеке. Я могу себе представить, что JLS говорит - где-то, все еще глядя - что эту временную переменную нужно проверить, чтобы убедиться, что она является неизученным типом (так как вы знаете, что это не поддерживается). –
Действительно, он работает, если вы выполняете разыменование в методе, например 'static void foo (Container c) {c.getArray(). GetClass(); } ' –
Есть интересная разница в байт-коде, если вы меняете' 'на'