2015-04-01 4 views
2

Почему мы должны делать Оборонительное копирование, чтобы достичь Непрерывного класса? Посмотрите на этом коде:Java Оборонительное копирование и непреодолимое

public final class EmailMessage { 
    private final String from; 
    private final String to; 
    private final String message; 
    private final Date date; 

    public EmailMessage(String from, String to, String msg, Date date) 
    { 
     this.to = to; 
     this.from = from; 
     this.message = msg; 
     this.date = new Date(date.getTime());// instead of date; 
    } 

    public String getFrom() 
    { 
     return(from); 
    } 

    public Date getDate() { 
     return(new Date(date.getTime()); // instead of Date 
    } 
} 

Почему это не будет Неизменным, если мы не делали оборонительное копирование?

+4

, потому что 'date' класс является изменяемым, даже если объявить его экземпляр окончательным, стоимость все еще могут быть изменены 'setDay()' и другими сеттерами. Копирование 'date' из аргумента конструктора, вы не можете гарантировать, что ссылки не будут храниться во внешнем коде, что позволит изменить. –

+0

Эта проблема плохого дизайна решена в пакете 'java.util.time' в Java 8, где вы должны использовать' LocalDate', 'LocalTime' и другие классы, которые являются полностью неизменными и безопасными. –

+0

вы можете использовать jodatime для удаления проблем с дизайном или java.util.time (из Java 8) – ha9u63ar

ответ

1

Для достижения неизменности вы должны сделать копии всех изменяемых объектов, переданных в ваш конструктор, а также вернуть копии для всех изменяемых объектов, хранящихся внутри вашего класса, если таковые имеются.

  • Если вы не сделали копию даты, переданной вам, вызывающий может изменить дату после того, как объект был создан, эффективно его мутируя.
  • Если вы не вернете копию из получателя изменчивого объекта, вызывающие могут мутировать объект, который они получают от вас, эффективно изменяя ваш объект.

В вашем конкретном примере класс Date изменен. Если йо пропустить копирование в конструкторе, вредоносный код может это сделать:

Date d = new ... 
EmailMessage msg = new EmailMessage("lazy dog", "quick brown fox", "Jump!", d); 
d.setTime(d.getTime()+12345); // Changes the date inside msg 

Если вы пропустите вторую копию, абоненты могут сделать это:

EmailMessage msg = ... 
Date d = msg.getDate(); 
d.setTime(d.getTime()+12345); // Changes the date inside msg 
1

Потому что в противном случае можно изменить объект государство. Давайте представим, что ваш метод getDate является следующее:

public Date getDate() { 
    return date; // instead of Date 
} 

И мы используем это следующим образом:

EmailMessage msg = new EmailMessage(...); // initialization 
Date date = msg.getDate(); 
date.setTime(...); //ooops, our msg object has another date now 
Смежные вопросы