import java.util.Arrays;
public class Amigo {
public static void main(String[] args) {
int[][] matrix = {
{1, 2, 3, 4, 5},
{5, 4, 3, 2, 1}
};
System.out.println(Arrays.deepToString(matrix));
int[] tmp = matrix[0]; // Присвоили массиву tmp ссылку на массив matrix[0]
System.out.println(Arrays.toString(tmp));
matrix[0] = matrix[1]; // Присвоили ссылке matrix[0] ссылку matrix[1]
System.out.println(Arrays.toString(tmp));
System.out.println(Arrays.deepToString(matrix));
matrix[1] = tmp; // По сути, присвоили ссылку tmp(== matrix[0]) ссылке matrix[1]
System.out.println(Arrays.deepToString(matrix));
matrix[1][2] = 222;
System.out.println(Arrays.toString(tmp));
System.out.println(Arrays.deepToString(matrix));
tmp[3] = 144;
System.out.println(Arrays.toString(tmp));
System.out.println(Arrays.deepToString(matrix));
}
}
Доброй ночи xD
Читая лекции наткнулся на пример, где объяснялось, как в массиве двумерном поменять строки местами, но как-то в голову не лезет, почему так выходит, ведь при замене элементов, если мы на них ссылаемся в другом массиве, элементы заменяются и в самом первом. Выше я расписал пример из лекции + добавил от себя, чтоб было понятно, что я имею ввиду.
Был создан двумерный массив с 5 значениями в каждой строке. Далее, был создан еще один массив tmp, которому присвоили ссылку(значения?) элемента matrix[0]. Все хорошо, никаких проблем не вижу.
Однако дальше, элементу matrix[0], в котором находится ссылка на массив значений {12345}, был присвоен элемент matrix[1], в котором находится ссылка на массив {54321}.
Вот тут и начинается загвоздка, я не понимаю, почему при присвоении matix[1] к matrix[0], наш tmp так и остался со ссылкой на массив значений который раньше был matrix[0] и не поменялся?
Если посмотреть на вывод значений на экран, в самой matrix значения поменялись, все логично, мы изменили элемент, было
[[1, 2, 3, 4, 5], [5, 4, 3, 2, 1]]
стало
[[5, 4, 3, 2, 1], [5, 4, 3, 2, 1]]
однако, tmp как был [1, 2, 3, 4, 5] так им и остался, но ведь не должен, теперь по этой ссылке находится иные значения. Мы не создавали новый отдельный массив, например через существующие методы с заносом туда данных из matrix, это все тот же tmp ссылающийся на элемент matrix[0], но почему-то не принимающий новые значения, а оставляющий старые [[1, 2, 3, 4, 5].
Далее мы присваиваем matrix[1] = tmp и вуаля, мы перевернули строку.
Затем, для примера, я написал еще код с изменением элементов внутри массива matrix[1][2] и вывел результаты, значения в tmp и строке matrix[1] изменились, тоже самое для tmp, и они снова изменились и там и там, что логично и правильно. Но когда мы делаем тоже самое для ссылок выше, tpm при изменении matrix[0] = matrix[1], все равно остался со старыми значениями matrix[0].
Вывод - ссылка как элемент, которая была присвоена другому массиву, в этом другом массиве не изменяется в случае когда мы изменяем элемент на другую ссылку в изначальном массиве? В обе стороны меняются только значения элементров внутри обычного массива?
Спасибо. Дай Диего здровья тому, кто ответит, а то получилось какое-то масло масляное(3:33 на часах), но надеюсь, мой ход мыслей будет понятен 🙃fFamous
51 уровень
Замена элементов в массиве в виде ссылок
Комментарии (8)
- популярные
- новые
- старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Justinian Judge в Mega City One Master
14 июля 2021, 02:14
Раза три перечитал, не совсем понял, но попробую рассказать, что понял.
почему если Маша даст яблоко Коле, у Пети должно поменяться количество яблок?
В джаве есть переменные ссылочного типа и примитивы.
Переменная ссылочного типа выглядит так:
Cat cat = new Cat();
int[] array = {1};
Переменная ссылочного типа имеет три основных элемента:
ТипПеременной - Cat, int[]
имяПеременной - cat, array
значение переменной - это ссылка на объект в памяти.
У примитивов есть тип переменной, имя, но значение не является ссылкой, а является конкретным значением примитива.
То есть в памяти, грубо говоря хранится так:
int[] | cat | 23gf34a1
Cat | cat | 23ad34
Dog | dog | 345d3e
int | i | 25
double | d | 0.34
boolean | b | true
То есть, у примитивов нету ссылок, переменные хранят сами значения.
А вот у ссылочных типов в качестве значения хранится адрес памяти объекта, на который ссылаются.
Что представляют собой массивы, это объекты, которые состоят из ячеек, в которых хранятся элементы определенного типа.
Если массив ссылочного типа - то в качестве элементов, будут ссылки на объекты, например:
Сat[] cats = { ...
String[] strings = {...
в памяти будут примерно так выглядит
Сat[] | cats | 23gf34a1
String[] | strings | 23ad34
как видим у них есть адреса - это ссылка на сам массив, который находится в памяти.
А по этим адресам мы видим, примерное состояние памяти адреса и что содержится:
23gf34a1:
[0] = 32d73a
[1] = 19b3d5
[2] = 28c31
..
...
23ad34:
[0] = 1da92
[1] = 3b341
[2] = 2bc4e
..
32d73a:
Кот Мурка
19b3d5:
Кот Василий
28c31:
Кот Рыжик
1da92:
"Aibolit"
3b341:
"Gena"
2bc4e:
"Masha" +2
Justinian Judge в Mega City One Master
14 июля 2021, 02:14
Что мы видим, переменные ссылаются на массивы.
А сами массивы содержат ячейки, в которых находятся...ссылки. Потому что массивы ссылочного типа, то есть хранят объекты, и за каждым адресом в массиве, какой-то Кот или какая-то строка.
С массивами примитивного типа по другому, как мы знаем примитивы содержатся в виде значений, а не отдельных объектов. Поэтому массив будет выглядит так:
int[] array = {1, 2, 3};
int[] | array | 23gf34a1
....
23gf34a1 :
[0] = 1
[1] = 2
[2] = 3
То есть хранятся сами значения.
Также есть у нас оператор присвоение =. Он у нас присваивает ЗНАЧЕНИЕ ССЫЛКИ.
Как работает оператор присвоение. Вычисляется правая сторона и ИТОГ операции, присваивается переменной слева. Это будет либо ссылка (для переменной ссылочного типа, например массива) либо значение копируется для примитива.
int a = 5;
int number = а;
в первой строке, у нас а = 5. Во второй строке, переменной присвоится значение 5, фактически скопируется. Поэтому никакие изменение переменных примитивов не влияют друг на друга, поскольку нету одного объекта и много ссылок. Есть просто много копий значений, и у каждой переменной своя копия.
А вот для переменных ссылочного типа, будет другое:
Cat cat = new Cat();
Cat cat2 = cat;
здесь у нас объект в памяти один. Запомни, видишь ключевое слово new - гарантировано создается один объект. Как минимум один )
а во второй строке, у нас просто идет копирование значения ссылки cat, то есть ссылки на объект в памяти Кот.
В итоге. Кот, один. Объект в памяти один.
А ссылки две, cat и cat2. В Изучаем Джава хорошая аналогия, ссылка как пульт от телевизора.
То есть телевизор (Кот) один.
А пультов может быть много, и с каждого можно управлять (Менять состояние) объекта.
Забегая наперед , при передаче переменных в методе, создаются КОПИИ значений переменных, либо копия значения примитива, либо копия значения ссылочной переменной, копия ссылки.
А теперь к самому интересному.
+1
Justinian Judge в Mega City One Master
14 июля 2021, 02:15
Что такое многомерные массивы, фактически, двумерных массивов в джава не существует.
То как мы , представляем матрицу, это условность.
В джаве, есть МАССИВЫ МАССИВОВ. То есть каждая размерность массива, 2-х мерный, 3х мерный и тд, это просто добавляется глубина вложенности. Массив массивов. Массив массивов массивов и тд.
Это в принципе хорошо видно по объявлению массива:
Как он выглядит в памяти:
int[][] | matrix | 156ab4c
156ab4c: //это массив №1 в памяти
[0] = 431b9
[1] = 220e3
...
431b9: // это массив №2 в памяти
[0] = 1
[1] = 2
[2] = 3
...
220e3: // это массив №3 в памяти
[0] = 4
[1] = 5
[2] = 6
Насколько я понимаю, основная твоя ошибка была в том, что ты посчитал, что можно присваивать переменной абстракцию - первый подмассив, второй подмассив.
int[] tmp = matrix[0];
но это не присвоение , это называется маппинг, и в джаве такого нету (такого маппинга массивов)
Смотри, мы можем написать так?
int number = 5 * 2 + 1;
или
int number = getNumber();
ответ да, можем.
Что здесь произойдет, СНАЧАЛА, правая часть схлопнется до одного значения - произведутся все нужные вычисления, вызовутся все методы и тогда РЕЗУЛЬТАТ уже будет присваивается.
Что происходит в строке:
int[] tmp = matrix[0];
?
Квадратные скобки это оператор. Оператор доступа к элементу массива.
Это приблизительно тоже самое что и
int number = getNumber();
то есть, сначала вызовется метод getNumber() или в нашем случае с matrix[0], пойдет обращение к элементу.
Что делает оператор квадратные скобки (круглые скобки , кстати это тоже оператор),
ОН ОБРАЩАЕТСЯ К МАССИВУ И ВОЗВРАЩАЕТ ЕГО ЭЛЕМЕНТ С УКАЗАННЫМ ИНДЕКСОМ +1
Justinian Judge в Mega City One Master
14 июля 2021, 02:15
То есть, matrix[0] обратится к элементу массива матрикс с индексом 0, это первый подмассив, или по нашей классификации Массив №2, и потом ВЕРНЕТ ссылку на 431b9 (массив №2, первый подмассив с индексом 0- сверься с моделью памяти выше).
Нет и не может быть никакой привязки, мол tmp ссылается именно на matrix[0], нет.
Что фактически ты сделал в коде, ты сделал своп - обмен:
Было так:
ты сделал
int[] tmp = 431b9
потом обменял ссылки через временную переменную и получилось так:
то есть подмассивы поменялись местами.
Но переменная tmp, как ссылалась на 431b9, так и ссылается.
Ты это можешь проверить так:
проверить адрес объекта.
Вначале и конце программы.
Поэтому все логично, вся загвоздка в этом:
int[] tmp = matrix[0];
ты не присваиваешь привязку к matrix[0] , ты просто обращаешься к объекту, который лежит в индексе 0, и поскольку потом меняешь местами, то твой tmp как ссылался на тот массив, так и продолжает ссылаться.
Грубо говоря, твоя переменная tmp вообще не знает, что есть какая-то матрица, какие-то там matrix[0] или matrix[1] .
tmp просто ссылается на обычный одномерный массив.
Просто совокупность таких массивов и составляет двумерный.
А в трехмерном, как ты можешь догадаться, в подмассивах бы были не числа, а ссылки на другие массивы. +1
fFamous
14 июля 2021, 03:07
"int[] tmp = matrix[0];
ты не присваиваешь привязку к matrix[0] , ты просто обращаешься к объекту, который лежит в индексе 0, и поскольку потом меняешь местами, то твой tmp как ссылался на тот массив, так и продолжает ссылаться."
Вот в этом и загвоздка. Я думал, что она должна быть(привязка) в массивах, так как ссылка является элементом со своим индексом, как и обычное значение.
Мне казалось, что:
когда мы присваиваем другому массиву элементы первого, то изменяя эти элементы у второго, они меняются у первого и обратно. Окей, все понятно, так устроен массив. До этого у нас были только обычные переменные, и если:
num останется 5, а num2 станет 6, окей, такое же будет если обернуть их в Integer, а это уже объект.
Массивы же работают иначе, в них, если мы присвоим один массив другому, то меняя у другого массива значения, они также будут манятся у первого:
Просто я сделал вывод, что элемент - первостепенен и не важно, что там, обычное значение или ссылка, если мы присвоили элемент другому массиву, то он должен измениться как при изменении в основном, так и при изменении во втором - у обоих. Мне казалось, что элемент во втором - !ВСЕГДА лишь "отражение" первого, но как видно с ссылками, он все же принимает ссылку по элементу и сохраняет ее в себе, а на изменение элемента у основного массива(где теперь другая ссылка) - не реагирует и продолжает сохранять эту ссылку 😉
Потом еще раз обязательно перечитаю твое сообщение :D
Спасибо.
+1
fFamous
14 июля 2021, 03:18
Сейчас еще больше дошло, у нас же получается, если массив в массиве -
ССЫЛКА--|--> ССЫЛКИ--|-->Объекты; и не важно, что мы взяли ссылку из массива, если мы заменим в массиве1 эту ссылку на объект, она все еще будет существовать как ссылка на объект и будет все также присвоена массиву2. А вот изменяя ее, мы уже изменяем сам объект... В общем, в топку эти элементы и индексы xD
+1
Justinian Judge в Mega City One Master
14 июля 2021, 05:20
Да, вроде так.
То есть, ты стоишь в комнате, перед тобой телевизор Тошиба.
Ты привязал к нему пульт 1.
Потом этот телевизор унесли и принесли Самсунг.
И ты, в своем посте спрашивал, почему твой пульт не работает, ведь ты направляешь его в то же место в комнате, где и стоял предыдущий телевизор.
Но пульт привязывается не к месту, а к конкретному телевизору.
Переменная хранит не на абстрактный индекс массива ссылку, а на конкретный объект.
В данном случае, по сути, матрица это один массив, который состоит из двух самостоятельных массивов. Их как телевизоры, можно двигать туда сюда, но привязанные пульты будут четко работать с тем ТВ, к которому привязали. От места не зависит.
Пока не поменяешь ссылку на другой объект.
+2
fFamous
14 июля 2021, 05:24
Ага-ага :) В общем, вникаю по тихой. Спасибо!
+1