#java
#java
Вопрос:
Я беру так:
Collection<TaskComment> commentsCollection = task.getComments();
ArrayList<TaskComment> comments = new ArrayList<>(commentsCollection);
for(TaskComment cmnt : comments){
cmnt.setUser(commentUser.getLogin());
cmnt.setCreatedAtString(cmnt.getCreatedAt().format(DateTimeFormatter.ofPattern(Constants.DATE_TIME_FORMAT)));
}
Здесь я беру комментарии и помещаю их в коллекцию, а затем в arraylist. Затем я манипулирую комментариями с помощью методов класса DTO.
Но когда я меняю cmnt
, комментарии от task.getcomments
меняются.
Я думаю, что этого кода достаточно, но я могу дать больше кода, если вы хотите. Почему это меняется? Предполагалось, что это не изменится, потому что я переместил его в коллекцию, а затем в массив?
Я этого не делаю:
repository.save(task);
после того, как я обработаю комментарий, поэтому он не должен сохраняться в базе данных? Итак, почему
task.getComments();
вернуть измененные данные? Я не сохранил в базе данных?
Комментарии:
1. Я не делаю этого: repository.save (task); после того, как я манипулировал, поэтому он не должен сохраняться в базе данных? Итак, почему task.getComments(); приносит измененные данные? Я не сохранил в базе данных?
Ответ №1:
Это потому, что вы все еще смотрите на те же TaskComment
объекты.
Ссылки на конкретный комментарий могут быть в двух коллекциях, commentsCollection
и comments
, но это только один объект. Не имеет значения, как вы получаете объект, если вы манипулируете им, он меняется.
Представьте свои объекты, в данном случае комментарии, в виде блоков. Вы привязываете красную строку к каждому блоку и передаете строки Алисе для хранения. Затем вы привязываете синюю строку к каждому блоку и передаете эти строки Бобу для хранения.
Теперь предположим, что Боб тянет за строку и получает поле. Он открывает коробку, кладет в нее шарик и засовывает коробку обратно на свое место.
Теперь Алиса тянет за строку для этого поля и получает поле. Если она откроет его, она найдет в нем шарик.
Что произойдет, если вы вызовете task.getComments();
снова, зависит от реализации. Если вы не сохраняли данные в базе данных и если этот метод получает их из базы данных каждый раз, вы не должны видеть никаких изменений в этих комментариях. Это как если бы вы получили новый набор блоков для Алисы.
Однако гораздо более вероятно, что когда вы загружаете Task
из базы данных, она загружает связанные с ней комментарии, добавляя их как свойство задачи. Затем, при каждом вызове для получения комментариев, вы получаете их не из базы данных, а из объекта Task. И к этим комментариям привязаны строки как у Алисы, так и у Боба.
Комментарии:
1. Можем ли мы сказать, что это ссылка на объект, а затем манипуляция выполняется над самим объектом. ?
2. Итак, как я могу справиться с этим? Мне нужно передать во внешний интерфейс разные комментарии, но я не могу это изменить.
3. Я не делаю этого: repository.save (task); после того, как я манипулировал, поэтому он не должен сохраняться в базе данных? Итак, почему task.getComments(); приносит измененные данные? Я не сохранил в базе данных?
4. @SQB , поэтому я очень смущен, передается ли Java по значению или ссылке, потому что все говорят, что она передается по значению 🙂
Ответ №2:
Это происходит потому, что, выполнив приведенную ниже строку, вы получите коллекцию ссылок, которая содержит фактические объекты
Collection<TaskComment> commentsCollection = task.getComments();
Нравится
commentsCollection
--> 0th element in commentsCollection --> (TaskComment object 1)
--> 1st element in commentsCollection --> (TaskComment object 2)
--> 2nd element in commentsCollection --> (TaskComment object 3)
Теперь, когда вы скопируете его в комментарии ArrayList
ArrayList<TaskComment> comments = new ArrayList<>(commentsCollection);
но все равно это будет похоже
comments
--> 0th element in comments --> (TaskComment object 1)
--> 1st element in comments --> (TaskComment object 2)
--> 2nd element in comments --> (TaskComment object 3)
И теперь, когда вы пытаетесь получить доступ к своим объектам, вы фактически вносите изменения в объекты TaskComment (1, 2 и 3), вот почему task.getcomments()
меняются.
Комментарии:
1. Итак, как я могу справиться с этим? Мне нужно передать во внешний интерфейс разные комментарии, но я не могу это изменить.
2. Если вам это нужно, поэтому вы отправляете его во внешний интерфейс, попробуйте создать новый класс ответов TaskCommentResponse (используя тот же TaskComment), а затем скопируйте каждый TaskComment в новый или используйте clone
3. Я не делаю этого: repository.save (task); после того, как я манипулировал, поэтому он не должен сохраняться в базе данных? Итак, почему task.getComments(); приносит измененные данные? Я не сохранил в базе данных?
4. Возможно, вы используете @Transactional, который автоматически сохраняет измененные объекты в БД.
5. Нет, он не сохраняется в БД. при следующем вызове снова появляются неизмененные значения. task.getcomments изменяется только временно, но я этого не понимаю.
Ответ №3:
В вашем примере вы создаете только 1 объект, task.getComments();
на который ссылаются обе commentsCollection
и comments
ссылочные переменные.
Следовательно, изменения в объекте будут отражены в обеих ссылочных переменных.
Collection<TaskComment> commentsCollection = task.getComments();
ArrayList<TaskComment> comments = new ArrayList();
for(TaskComment cmnt : commentsCollection ){
comments.add(cmnt.clone());
}
Переопределите clone
метод в TaskComment
классе следующим образом:
public Object clone() {
//deep copy
TaskComment newObject = new TaskComment();
//Now copy each property of original object to the new object.
//e.g. newObject.setProperty(this.getProperty());
return newObject;
}
Комментарии:
1.Итак, как я могу справиться с этим? Мне нужно передать во внешний интерфейс разные комментарии, но я не могу это изменить.
2. Я не делаю этого: repository.save (task); после того, как я манипулировал, поэтому он не должен сохраняться в базе данных? Итак, почему task.getComments(); приносит измененные данные? Я не сохранил в базе данных?
3. @отметьте, что вам нужно глубоко СКОПИРОВАТЬ ваш
commentsCollection
список вcomments
список.
Ответ №4:
В вашем коде фактический объект, т. е. commentsCollection
ссылка, будет присвоен comments
коллекции, и после этого вы повторяете эту коллекцию, и при повторении этого нового объекта коллекции, т. Е. comments
, вы изменяете фактическую ссылку, т.Е. commentsCollection
.
В Java вы можете создать один объект и ссылаться на него с помощью нескольких ссылок, которые косвенно содержат указатель на объект. Вызов метода мутатора для любой ссылки эффективно модифицирует единственный объект, обновляя таким образом все остальные ссылки.
Комментарии:
1. Хороший первый ответ, но его можно улучшить, добавив образцы кода, где это возможно 🙂