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")
);