2013-07-18 5 views
6

Я изучаю концепцию неизменности.Java Неизменяемые объекты

Я понимаю, что неизменяемые объекты не могут изменить свои значения после создания объекта.

Но я не понял следующие применения неизменяемых объектов.

Они

  • автоматически поточно-и не имеют никаких проблем с синхронизацией. How ? Proof ?
  • не нужен конструктор копирования. How ? Any example ?
  • не нужна реализация клона How ? Any example ?
  • не должен быть скопирован, защищаясь при использовании в качестве поля How ? Any example ?
  • всегда есть "failure atomicity" (a term used by Joshua Bloch): если непреложный объект генерирует исключение, он никогда не остается в нежелательном или неопределенное состояние. How ? Any example ?

Может кто-то пожалуйста, объясните каждую из этих точек подробно с примерами поддерживающих его?

Спасибо.

+3

Я проголосовал за закрытие. Это пять вопросов, объединенных в один, каждый из которых потребует широких подробных ответов. Не знаю, почему у этого есть три голоса. –

+0

Это какая-то домашняя работа? Также обратите внимание, что сразу возникает много вопросов, а также некоторые вопросы основаны на мнениях.Пожалуйста, сделайте свой вопрос более конкретным и покажите нам, что вы пробовали. –

+0

Это пахнет немного, как домашнее задание - вы можете задавать вопросы, которые суть, а не общий. Пойдите и попытайтесь решить эти вопросы самостоятельно - если вы застряли, мы можем помочь – Mirco

ответ

10

..are автоматически поточно-и имеют синхронизация не выдает

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

Пример: A String. Два потока могут быть переданы одинаково String без проблем, так как ни один из них не может мутировать его никак.

не нужен конструктор копирования

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

Конструкторы копирования обычно используются на объектах, которые вы хотите изменить, не затрагивая оригинал. Это всегда так (по определению) с неизменяемыми объектами.

В случае String все методы и оператор + возвращают новый String s.

не нужна реализация клона

см выше.

не должны быть скопированы, защищаясь при использовании в качестве поля

Однажды я сделал что-то глупое. У меня был набор перечислений в списке:

private static final List<Status> validStatuses; 

static { 
    validStatuses = new ArrayList<Status>(); 
    validStates.add(Status.OPEN); 
    validStates.add(Status.REOPENED); 
    validStates.add(Status.CLOSED); 
} 

Этот список был возвращен из метода:

public static List<Status> getAllStatuses() { 
    return validStates; 
} 

Я извлеченной этот список, но только хотел показать открытые состояния в интерфейсе:

List<Status> statuses = Status.getAllStatuses(); 
statuses.remove(Status.CLOSED); 

Отлично, это сработало! Подождите, теперь все статусные списки показывают только те два - даже после обновления страницы! Что случилось? Я изменил статический объект. К сожалению.

Я мог бы использовать защитное копирование по возвращенному объекту getAllStatuses. Или, я мог бы использовать что-то вроде Guava's ImmutableList в первую очередь:

private static final List<Status> validStatuses = 
    ImmutableList.of(Status.OPEN, Status.REOPENED, Status.CLOSED); 

Тогда, когда я сделал что-то тупое:

List<Status> statuses = Status.getAllStatuses(); 
statuses.remove(Status.CLOSED); // Exception! 

всегда есть «отказ атомарность» (термин, используемый Джошуа Блох): если неизменяемый объект выдает исключение, он никогда не остается в нежелательном или неопределенном состоянии.

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

2

Они автоматически поточно- и имеет никакой синхронизации не выдает

Да из-за гарантии, предоставленной моделью Java памяти для final fields:

конечных поля также позволяют программистам реализовать нить - безопасные неизменяемые объекты без синхронизации. Нитебезопасный неизменяемый объект рассматривается как непреложный для всех потоков, даже если гонка данных используется для передачи ссылок на неизменяемый объект между потоками.

Нельзя копировать оборонительно при использовании в качестве поля Как? Любой пример?

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

Следствие: вам не нужно копировать/клонировать неизменяемые объекты.

всегда есть «отказ» атомарность

Неизменный объект не изменится, как только она правильно построена. Таким образом, либо сбой конструкции, либо вы получаете исключение, либо нет, и вы знаете, что объект находится в согласованном состоянии.

+0

Но String - неизменяемый объект по умолчанию, но все же мы делаем строковые поля внутри класса неизменяемого объекта «окончательными»? Зачем ? – tmgr

+0

Чтобы объект был неизменным, все его поля должны быть окончательными (кроме ограниченных и сложных исключений). Поэтому, если ваш объект содержит поле строки, он должен быть помечен как final. В противном случае вы потеряете гарантию безопасности потока, даже если строка не может быть изменена. См. Также, для получения дополнительной информации: http://stackoverflow.com/questions/16061030/must-all-properties-of-an-immutable-object-be-final – assylias

+1

@ tm99 Если вы не отметите поле String как окончательное , вы не потеряете безопасность потока на самой строке (что является неизменным). Вы теряете его на объекте, у которого есть поле String, что не является окончательным! – afsantos

1

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

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

0

Автоматически поточно

  • , потому что они не могут быть изменено (не может мутировать) - любой поток, обращающийся к нему, находит объект в том же состоянии. Таким образом, нет таких ситуаций, как один поток изменяет состояние объекта, затем второй поток берет на себя и изменяет состояние объекта, а затем сначала берет на себя никакой ключ, что он был изменен кем-то другим
  • хорошим примером является ArrayList - если один поток выполняет итерацию через свои «элементы», а второй поток удаляет некоторые из них, первый поток затем генерирует какое-то исключение параллелизма. С неизменным списком это предотвращается

Copy конструктор

  • это не значит, что она не может иметь конструктор копирования. Это конструктор, к которому вы передаете объект того же типа, и вы создаете новый объект как копию данного объекта. Это всего лишь предположение, но зачем вы копируете объект, который всегда находится в одном состоянии?
public class A 
{ 
    private int a; 

    public A(int a) 
    { 
     this.a = a; 
    } 

    public A(A original) 
    { 
     this.a = original.a; 
    } 

}

Реализация клона

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

Оборонительного копирования

  • оборонительного что когда вы устанавливаете объект в поле, вы создаете новый объект того же типа, который является копией оригинала
  • Example
Смежные вопросы