Решил вот я подучить Java, сижу, разбираюсь. Подскажите мне кто-нибудь, что происходит в тестовом коде. Суть кода вот в чём. Заводим одномерный массив int[8] из нулей в процедуре test, передаём его в процедуру modify, и в этой процедуре заменяем, например, первый элемент на 1. Вопрос: изменится ли содержание массива в процедуре test? Поскольку в Java нет VAR-параметров, то вроде бы модификация должна остаться локальной в процедуре modify, и по возвращении в test массив снова должен быть нулевым (как если бы в modify передавалась копия массива). Тест VAR-test1 показывает, что это не так: массив оказывается модифицирован в обоих процедурах, как будто это VAR-параметр. Хорошо, значит у нас массив в куче и мы передали ссылку на него. Чтобы избавиться от VAR-эффекта, при передаче параметра вызовем массив.clone(). В этом случае модификация в modify не "всплывает" обратно в процедуру test. Проблема решена.
Теперь попробуем то же самое проделать с двумерным массивом. Здесь без вызова .clone() имеем VAR-эффект, как и в первом случае, НО с добавлением вызова .clone() VAR-эффект не пропадает! Я попробовал добавить проверку .equals(), и увидел, что проверка возвращает истину при передаче исходного массива и ложь при передаче клона. Это так и должно быть. Тем не менее, изменение массива, который !equals(), изменяет исходный массив аналогично VAR-параметру.
Объясните мне, пожалуйста:
- есть ли в Java VAR-параметры? Если да, то ими могут быть только массивы или ещё что-то?
- почему .clone() не срабатывает для двумерного массива так же, как срабатывает для одномерного?
- как так получается, что два массива, которые не .equals(), ссылаются на общие данные?
Код (на метод test1 не обращайте внимание):
Код:
import java.util.Arrays;
import java.util.List;
public class MyTest {
private static int[] arr8;
private static int[][] arr88;
private static void test1 () {
// note that Arrays.asList returns a collection, which, being modified, modifies the originally passed array
String[] arr = {"1", "2", "3"};
List<String> lst = Arrays.asList(arr); // use arr.clone() to unlink from the collection
lst.set(0, lst.set(2, lst.get(0))); // swap 0 and 2
for (String i : lst) {
System.out.print(i);
}
System.out.println();
// note that in 'arr' the elements are swapped, too
for (String i : arr) {
System.out.print(i);
}
System.out.println();
}
private static void test2 () {
// this test shows that arrays are passed by reference, i.e. as VAR-parameters
// local variables are no different from the global static ones
arr8 = new int[8];
Arrays.fill(arr8, 0);
modifyArr8(arr8);
System.out.print("VAR-test1: ");
System.out.println(arr8[0] == 1 ? "Modified" : "Not modified");
// to avoid modification, use .clone() method
Arrays.fill(arr8, 0);
modifyArr8(arr8.clone()); // clone the array
System.out.print("VAR-test1(clone): ");
System.out.println(arr8[0] == 1 ? "Modified" : "Not modified");
// this test shows that .clone() doesn't work for two-dimensional arrays
arr88 = new int[8][8];
Arrays.fill(arr88[0], 0);
modifyArr88(arr88);
System.out.print("VAR-test2: ");
System.out.println(arr88[0][0] == 1 ? "Modified" : "Not modified");
Arrays.fill(arr88[0], 0);
modifyArr88(arr88.clone()); // clone the array
System.out.print("VAR-test2(clone): ");
System.out.println(arr88[0][0] == 1 ? "Modified" : "Not modified");
}
private static void modifyArr8 (int[] arr) {
System.out.print("modifyArr8: equals before modification: ");
System.out.println(arr.equals(arr8));
arr[0] = 1;
System.out.print("modifyArr8: equals after modification: ");
System.out.println(arr.equals(arr8));
}
private static void modifyArr88 (int[][] arr) {
System.out.print("modifyArr88: equals before modification: ");
System.out.println(arr.equals(arr88));
arr[0][0] = 1;
System.out.print("modifyArr88: equals after modification: ");
System.out.println(arr.equals(arr88));
// NB! .equals() returns false for the .clone()d object, but the original one gets modified anyway
}
public static void main (String[] args) {
test1();
test2();
}
}
Выдача при запуске:
Код:
321
321
Equals before modification: true
Equals after modification: true
VAR-test1: Modified
Equals before modification: false
Equals after modification: false
VAR-test1(clone): Not modified
Equals before modification: true
Equals after modification: true
VAR-test2: Modified
Equals before modification: false
Equals after modification: false
VAR-test2(clone): Modified