Решил вот я подучить 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