Java неизменный объект вопрос
String abc[]={"abc"};
String def[]={};
def=abc;
def[0]=def[0]+"changed";
System.out.println(abc[0]);
изменив объект "def", также изменится мой объект abc. Помимо массива String [] эта характеристика имеет то, что другой объект Java имеет схожую характеристику? может объяснить больше? чтобы предотвратить изменение abc при изменении def, мне нужно будет выполнить def = abc.clone();
Ответы
Ответ 1
Вы смешиваете изменчивость/неизменяемость объекта с копированием ссылочных значений.
На этих диаграммах [var/index]
является ссылочной переменной, а {{an Object}}
является объектом.
String abc[]={"abc"};
String def[]={};
[abc] ------> {{a String[1]}}
[0] --------------> {{a String "abc"}}
[def] ------> {{a String[0]}}
Теперь вы указываете опорные переменные def
на тот же объект, что и опорная переменная abc
:
def=abc;
[abc] ------> {{a String[1]}}
/ [0] --------------> {{a String "abc"}}
/
[def] ---/ {{a String[0]}}
В этот момент массив нулевой длины невозможен и должен быть собран в мусор. Мы можем сузить наше обсуждение до массива длины один. Обратите внимание, что a String[]
- это массив ссылок. С помощью следующей строки вы изменили то, что единственный элемент в длине, на которую указывает один массив.
def[0]=def[0]+"changed";
[abc] ------> {{a String[1]}}
/ [0] ---------\ {{a String "abc"}}
/ \
[def] ---/ \--> {{a String "abcchanged"}}
Обратите внимание, что сам {{a String "abc"}}
не был мутирован. [abc]
и [def]
теперь указывает на тот же {{a String[1]}}
, который является изменяемым (т.е. вы можете сделать элементы массива, которые являются ссылками на объекты String
, указать на что-либо).
чтобы предотвратить изменение abc
при изменении def
, мне нужно будет сделать def = abc.clone()
;
Собственно, это не совсем точно. Посмотрим, что произойдет, если вы clone()
массив ссылок на изменяемый тип StringBuilder
.
StringBuilder[] abc = new StringBuilder[] { new StringBuilder("Hello") };
StringBuilder[] def = abc.clone();
def[0].append(" world!");
System.out.println(abc[0]); // prints "Hello world!"
Я не буду делать диаграммы для вас на этот раз, но вы можете легко нарисовать их на бумаге. Здесь происходит то, что даже если clone()
создает второй объект {{a StringBuilder[1]}}
со своим собственным элементом (т.е. def != abc
), этот элемент указывает на тот же объект {{a StringBuilder}}
(т.е. def[0] == abc[0]
).
Короче:
- Неизверженность означает, что объекты определенного типа не могут каким-либо образом изменить внешний наблюдатель
-
Integer
, String
и т.д. являются неизменяемыми.
- Обычно все типы значений должны быть
- Объекты массива изменяются
- Это может быть массив ссылок на неизменяемые типы, но сам массив является изменяемым
- Значение вы можете установить эти ссылки на все, что хотите.
- Также верно для массива примитивов
- Неизменяемый массив не будет практичным.
- Ссылки на объекты могут быть разделены
- Если объект изменчив, мутация будет видна через все эти ссылки.
Если вы хотите более глубокое понимание проблем, я рекомендую следующее:
Ответ 2
Неизменяемые объекты - это объекты, которые нельзя изменить после создания. String
- очевидный пример. Массивы изменяемы. Если вы хотите неизменную коллекцию, вместо этого используйте List
:
List<String> abc = Collections.unmodifiableList(
Arrays.asList("abc")
);
У взаимозаменяемых объектов есть мутаторы. Мутатором является любой метод, который изменяет состояние объекта. Сети - очевидный пример. Типичный неизменный объект будет выглядеть следующим образом:
public class Person {
private final String firstName;
private final String lastName;
private final Date dateOfBirth;
public Person(String firstName, String lastName, Date dateOfBirth) {
this.firstName = firstName;
this.lastName = lastName;
this.dateOfBirth = new Date(dateOfBirth.getTime());
}
public String getFirstName() { return firstName; }
public String getLastname() { return lastName; }
public Date getDateOfBirth() { return new Date(dateOfBirth.getTime()); }
}
Вообще говоря, для неизменяемых объектов все члены final
и неизменяемы. Date
- хороший пример проблемы выше. Date
не является неизменным, что многие (включая меня) рассматривают ошибку дизайна. В результате, будучи изменчивым, вы должны сделать много оборонительного копирования.
Ответ 3
просто для педантичности, нет объекта "abc" или "def". Там есть единственная String [], которая имеет abc, а затем def. Вот почему "оба объекта" изменились. Фактически, они ссылались на один и тот же объект.
Ответ 4
В простых выражениях это выглядит так:
Давайте предположим, что Sample будет классом, тогда
Sample sam1 = new Sample();
будет ясно объяснено, поскольку sam1 является ссылкой на созданный объект.
но
Sample sam2;
просто объявляет, что sam2 является ссылочной переменной типа Sample и не имеет объекта класса Sample, который указывает на него.
теперь, если мы сделаем эту операцию
sam2 = sam1;
то это означает, что ссылочные переменные указывают на один и тот же объект, и теперь можно ссылаться на этот объект, используя любую из двух ссылок.
Очевидно, что можно манипулировать полями, использующими действительные методы, используя любую из ссылок.
И это то, что было сделано и здесь.
String abc[]={"abc"};
String def[]={};
def=abc;
def[0]=def[0]+"changed";
и поэтому изменение def [0] также изменит abc [0].
Now when you clone you are creating a clone of the existent object.
The clone and the cloned objects independently exist
as 2 different objects and so the result of manipulations on one
is not reflected as you stated.
Ответ 5
В java вы всегда можете изменять элементы в массиве, независимо от типа массива. Рассмотрите возможность создания отдельной копии данных для защиты начального значения abc, если вы хотите сохранить данные в структуре массива:
String abc[]={"abc"};
String def[];
def = Arrays.copyOf(abc, abc.length);
В качестве альтернативы используйте решение cletus:
List abc = Collections.unmodifiableList(
Arrays.asList("abc")
);