поведение java.util.Date в глубокой копии - PullRequest
0 голосов
/ 20 декабря 2018

У меня установлена ​​64-разрядная операционная система Windows 7 Professional, и я работаю с JDK 7.

У меня есть класс Employee, который поддерживает копирование с помощью конструктора:

public class Employee {
   private int id;
   private String name;
   private java.util.Date hireDate;

   public Employee() { 
   } 

   public Employee(Employee e) {
      this.id = e.id;
      this.name = e.name;
      this.hireDate = e.hireDate;
   }

   // getters and setters
}

Для первого тестированияЯ создаю объект employee1:

Employee employee1 = new Employee();
employee1.setId(1);
employee1.setName("John");
employee1.setHireDate(new GregorianCalendar(2018, Calendar.DECEMBER, 19).getTime());

Затем я клонирую его в объект employee2;

Employee employee2 = new Employee(employee1);

Теперь мне сказали, что только примитивы и неизменяемые объекты не нуждаются в глубоком копировании, и поскольку java.util.Date не является ни примитивным, ни неизменным, поэтому я подумал, что это будет действовать как копирование ссылок, поэтому, если я изменю его в одном объекте, это также автоматически изменится во втором объекте.

Таким образом, я изменяю это во 2-м объекте:

employee2.setHireDate(new GregorianCalendar(2017, Calendar.FEBRUARY, 5).getTime())

, но когда я печатаю их обоих:

System.out.println("employee1.getHireDate()=" + employee1.getHireDate());
System.out.println("employee2.getHireDate()=" + employee2.getHireDate());

Я видел 2 разные даты.Что я понял неправильно?

Ответы [ 2 ]

0 голосов
/ 21 декабря 2018

Вы меняете дату найма каждого сотрудника на новый объект Date, , поэтому имеет смысл, что два значения независимы.

Проблема заключается в том, что после вызова конструктора копирования ониоба совместно используют один и тот же экземпляр Date, , который является изменяемым (с помощью его метода setTime ).Если сам объект Date (не свойство Employee) изменяется путем вызова его метода setTime, мы видим эффект:

Employee employee1 = new Employee();
employee1.setId(1);
employee1.setName("John");
employee1.setHireDate(new GregorianCalendar(2018, Calendar.DECEMBER, 19).getTime());

Employee employee2 = new Employee(employee1);

// Change the state of the Date object shared by both instances.
employee2.getHireDate().setTime(
    new GregorianCalendar(2018, Calendar.JANUARY, 19).getTimeInMillis());

System.out.println("employee1.getHireDate()=" + employee1.getHireDate());
System.out.println("employee2.getHireDate()=" + employee2.getHireDate());

Решение состоит в том, чтобы выполнить защитное копирование Date:

public Employee(Employee e) {
   this.id = e.id;
   this.name = e.name;
   this.hireDate = (e.hireDate != null ? (Date) e.hireDate.clone() : null);
}

Кроме того, ваши методы получения и установки должны делать одно и то же:

public Date getHireDate() {
    return hireDate != null ? (Date) hireDate.clone() : null);
}

public void setHireDate(Date newDate) {
    this.hireDate = (newDate != null ? (Date) newDate.clone() : null);
}

Таким образом, дата приема на работу не может быть изменена, кроме как путем вызова вашего метода setHireDate (или с отражением, но это отдельныйвыпуск).Класс Employee имеет полный контроль над своими собственными данными.

0 голосов
/ 20 декабря 2018

Попытайтесь понять внутренности.

Employee employee1 = new Employee();
employee1.setId(1);
employee1.setName("John");
employee1.setHireDate(new GregorianCalendar(2018, Calendar.DECEMBER, 19).getTime());

Когда вы сделаете это, у вас появится объект сотрудника, employee1, который имеет ссылку hireDate, которая указывает на объект Date, содержащий дату(19/12/2018).

Теперь, когда вы сделали это:

Employee employee2 = new Employee(employee1);

Оба объекта employee1 и employee2 имеют ссылку hireDate, которые указывают на Date объект, содержащий дату (19/12/2018).

Теперь, поймите это:

employee2.setHireDate(new GregorianCalendar(2017, Calendar.FEBRUARY, 5).getTime());

Когда вы сделаете это, новый Date объект будет создан new GregorianCalendar(2017, Calendar.FEBRUARY, 5).getTime()и теперь hireDate ссылка на объект employee2 указывает на этот Date объект.Не предыдущий.

Это означает, что hireDate ссылка на объект employee1 указывает на Date объект, содержащий дату (19/12/2018), а hireDate ссылка на объект employee2 указывает на Date объект, содержащий дату (5/2/2017).

Вот почему у вас разные даты.Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...