OberonCore
https://forum.oberoncore.ru/

Java: (двумерный массив).clone() = ?
https://forum.oberoncore.ru/viewtopic.php?f=26&t=2895
Страница 1 из 1

Автор:  Александр Ильин [ Среда, 06 Октябрь, 2010 16:19 ]
Заголовок сообщения:  Java: (двумерный массив).clone() = ?

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

Автор:  Александр Шостак [ Среда, 06 Октябрь, 2010 16:34 ]
Заголовок сообщения:  Re: Java: (двумерный массив).clone() = ?

Выскажу предположение. Массивы это объекты. Двумерные массивы - массивы объектов. Как и в javascript, передавая массив, вы передаёте объект и его изменение аналогично var-параметру. clone() создаёт новый массив и присваевает его элементам значения исходного массива. Только вот для двумерного массива эти значения сами объекты-массивы.

Автор:  Евгений Темиргалеев [ Среда, 06 Октябрь, 2010 16:35 ]
Заголовок сообщения:  Re: Java: (двумерный массив).clone() = ?

хехе. есть предположение, что клонируется массив ссылок на одномерные массивы :)

Автор:  Александр Ильин [ Среда, 06 Октябрь, 2010 16:49 ]
Заголовок сообщения:  Re: Java: (двумерный массив).clone() = ?

Действительно, .clone() клонирует только первое измерение двумерного массива.
Добавление вот такой процедуры помогает:
Код:
   private static int[][] deepClone (int[][] arr) {
      int[][] res = arr.clone();
      for (int i = 0; i < arr.length; i++) {
         res[i] = arr[i].clone();
      }
      return res;
   }
   

Автор:  Валерий Лаптев [ Среда, 06 Октябрь, 2010 17:36 ]
Заголовок сообщения:  Re: Java: (двумерный массив).clone() = ?

В Яве реализована следующая дисциплина передачи параметров по умолчанию:
1. Элементарные типы данным передаются по значению. Это те же самые типы, что и в С++.
2. Объектные типы ВСЕГДА передаются по ссылке.
Программист этим не управляет.
Кроме того, надо смотреть методы сравнения - в каких-то вариантах сравниваются тоже ссылки, а не сами объекты (просто подробностей не помню - надо документацию смотреть)

Автор:  Comdiv [ Среда, 06 Октябрь, 2010 18:22 ]
Заголовок сообщения:  Re: Java: (двумерный массив).clone() = ?

N-мерных массивов нет - есть только массивы массивов. Массивы - это объекты.

Всё передаётся по значению, в том числе и объекты. Точнее не сами объекты, а указатели на них. При работе с этими указателями как в Обероне происходит незримое разыменование, вот только зримое отсутствует. Нельзя сделать так a^ = b^, всегда присваиваются указатели.

Если не секрет, зачем Вам Java?

Автор:  Сергей Губанов [ Четверг, 07 Октябрь, 2010 14:35 ]
Заголовок сообщения:  Re: Java: (двумерный массив).clone() = ?

Путаница из-за терминологии.

В Яве аргументы в процедуры передаётся по значению, но Дельфийский, Явский и Шарповый "class" это "POINTER TO RECORD", а массив на самом деле не массив, а "POINTER TO ARRAY".

Автор:  Info21 [ Четверг, 07 Октябрь, 2010 15:35 ]
Заголовок сообщения:  Re: Java: (двумерный массив).clone() = ?

Сергей Губанов писал(а):
Путаница из-за терминологии.

В Яве аргументы в процедуры передаётся по значению, но Дельфийский, Явский и Шарповый "class" это "POINTER TO RECORD", а массив на самом деле не массив, а "POINTER TO ARRAY".
Путаница -- да, но как легко с ней разбираться, интерпретируя на Обероне.

Автор:  Александр Ильин [ Четверг, 07 Октябрь, 2010 20:13 ]
Заголовок сообщения:  Re: Java: (двумерный массив).clone() = ?

Comdiv писал(а):
Если не секрет, зачем Вам Java?
Для собеседования на работу.

Страница 1 из 1 Часовой пояс: UTC + 3 часа
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/