Это странно, но код говорит больше, чем слова, поэтому посмотрите на тест, чтобы увидеть, что я делаю. В моей текущей настройке (обновление Java 7 21 на 64-разрядной Windows) этот тест завершился неудачно с ArrayIndexOutOfBoundsException, но, заменив код метода тестирования на код с комментариями, он работает. И мне интересно, есть ли какая-то часть спецификации Java, которая объясняла бы почему.JVM ошибка? Значение поля кэшированного объекта вызывает ArrayIndexOutOfBoundsException
Мне кажется, что «майкл нестеренко» предположил, что значение поля массива кэшируется в стеке, перед вызовом метода и не обновляется при возврате из вызова. Я не могу сказать, является ли это ошибкой JVM или документированной «оптимизацией». Нет многопоточности или «магии».
public class TestAIOOB {
private String[] array = new String[0];
private int grow(final String txt) {
final int index = array.length;
array = Arrays.copyOf(array, index + 1);
array[index] = txt;
return index;
}
@Test
public void testGrow() {
//final int index = grow("test");
//System.out.println(array[index]);
System.out.println(array[grow("test")]);
}
}
Догадка, когда вы вызываете 'grow' из массива, он уже находится в стеке, и поэтому ссылка не обновляется, но если вы вызываете' grow' before и затем используете индекс, ссылка на массив загружается после его обновления и таким образом, он работает. просто догадка. возможно, просмотр байтового кода может помочь –
Я бы не назвал его «кэшированным в стеке». Я думаю, что это вопрос Java (langauge). Вы ссылаетесь на имя, которое разрешено * до *, используя/применяя разрешенное значение, связанное с ним. Поэтому, если имя перераспределено между ними, вы получили неправильное значение. –
Вот более простой тестовый пример: 'public class TestAIOOB {static Object [] array; static int reassign() {array = new Object [] {new Object()}; return 0; } public static void main (String [] args) {System.out.println (array [reassign()]); }} '. Это бросает (как и должно), и вы спрашиваете, почему. –