Что подразумевается под неизменным?

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

  1. Может ли кто-нибудь прояснить, что подразумевается под неизменным ?
  2. Почему String неизменяема?
  3. Каковы преимущества / недостатки неизменяемых объектов?
  4. Почему должен быть измененный объект, такой как StringBuilder , предпочтительнее, чем String и наоборот?

Хороший пример (на Java) будет действительно оценен.

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

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

например

 class Foo { private final String myvar; public Foo(final String initialValue) { this.myvar = initialValue; } public String getValue() { return this.myvar; } } 

Foo не должен беспокоиться о том, что вызывающий getValue() может изменить текст в строке.

Если вы представляете себе подобный class для Foo , но с StringBuilder а не как String как член, вы можете видеть, что вызывающий getValue() мог бы изменить атрибут Foo экземпляра Foo .

Также остерегайтесь различных видов неизменности, которые вы можете найти: Эрик Липперт написал статью в блоге об этом. В принципе, у вас могут быть объекты, интерфейс которых неизменен, но за кулисами действительно изменяет собственное состояние (и, следовательно, нельзя безопасно обмениваться между streamами).

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

Для неизменяемых строк существует много преимуществ:

Производительность: выполните следующую операцию:

 String substring = fullstring.substring(x,y); 

Основополагающий C для метода substring (), вероятно, выглядит примерно так:

 // Assume string is stored like this: struct String { char* characters; unsigned int length; }; // Passing pointers because Java is pass-by-reference struct String* substring(struct String* in, unsigned int begin, unsigned int end) { struct String* out = malloc(sizeof(struct String)); out->characters = in->characters + begin; out->length = end - begin; return out; } 

Обратите внимание, что ни один из символов не должен быть скопирован! Если объект String был изменен (символы могут меняться позже), вам придется скопировать все символы, иначе изменения в символах в подстроке будут отражены в другой строке позже.

Параллельность: если внутренняя структура неизменяемого объекта действительна, она всегда будет действительна. Нет никаких шансов, что разные streamи могут создать недопустимое состояние внутри этого объекта. Следовательно, неизменяемыми объектами являются Thread Safe .

Сбор мусора: сборщику мусора намного легче принимать логические решения о неизменяемых объектах.

Однако есть и минусы неизменности:

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

 foo = foo.substring(0,4) + "a" + foo.substring(5); // foo is a String bar.replace(4,5,"a"); // bar is a StringBuilder 

Две строки заменяют четвертый символ буквой «a». Мало того, что вторая часть кода более читаема, она быстрее. Посмотрите, как вам придется делать базовый код для foo. Подстроки просты, но теперь, потому что уже есть символ в пространстве пять, и что-то еще может ссылаться на foo, вы не можете просто изменить его; вам нужно скопировать всю строку (конечно, некоторые из этих функций абстрагируются на функции в реальном базовом C, но здесь нужно показать код, который выполняется в одном месте).

 struct String* concatenate(struct String* first, struct String* second) { struct String* new = malloc(sizeof(struct String)); new->length = first->length + second->length; new->characters = malloc(new->length); int i; for(i = 0; i < first->length; i++) new->characters[i] = first->characters[i]; for(; i - first->length < second->length; i++) new->characters[i] = second->characters[i - first->length]; return new; } // The code that executes struct String* astring; char a = 'a'; astring->characters = &a; astring->length = 1; foo = concatenate(concatenate(slice(foo,0,4),astring),slice(foo,5,foo->length)); 

Обратите внимание, что concatenate вызывается дважды, означая, что вся строка должна быть зациклирована! Сравните это с кодом C для работы bar :

 bar->characters[4] = 'a'; 

Операция с изменяемой строкой, очевидно, намного быстрее.

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

 // This will have awful performance if you don't use mutable strings String join(String[] strings, String separator) { StringBuilder mutable; boolean first = true; for(int i = 0; i < strings.length; i++) { if(!first) first = false; else mutable.append(separator); mutable.append(strings[i]); } return mutable.toString(); } 

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

Фактически String не является неизменным, если вы используете определение википедии, предложенное выше.

Состояние строки меняет постконструкцию. Взгляните на метод hashcode (). String кэширует значение hashcode в локальном поле, но не вычисляет его до первого вызова hashcode (). Эта ленивая оценка hashcode помещает String в интересную позицию в качестве неизменяемого объекта, состояние которого изменяется, но нельзя заметить, что оно изменилось без использования отражения.

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

Если состояние изменяется в неизменяемом объекте после его создания, но никто не может его видеть (без отражения), является ли объект еще неизменным?

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

Однако, чтобы уточнить, StringBuilder на самом деле является изменчивым объектом, а не неизменным. Регулярная строка java неизменна (это означает, что после ее создания вы не можете изменить базовую строку без изменения объекта).

Например, предположим, что у меня есть class ColoredString, который имеет значение String и цвет String:

 public class ColoredString { private String color; private String string; public ColoredString(String color, String string) { this.color = color; this.string = string; } public String getColor() { return this.color; } public String getString() { return this.string; } public void setColor(String newColor) { this.color = newColor; } } 

В этом примере ColoredString называется изменчивым, поскольку вы можете изменять (мутировать) одно из своих свойств ключа, не создавая новый class ColoredString. Причина, по которой это может быть плохо, – например, предположим, что у вас есть приложение GUI, которое имеет несколько streamов, и вы используете ColoredStrings для печати данных в окне. Если у вас есть экземпляр ColoredString, который был создан как

 new ColoredString("Blue", "This is a blue string!"); 

Тогда вы ожидаете, что строка всегда будет «Синяя». Если другой stream, однако, получил этот экземпляр и вызвал

 blueString.setColor("Red"); 

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

Чтобы воспроизвести, в Java, java.lang.String – неизменяемый объект (его нельзя изменить после его создания), а java.lang.StringBuilder – изменяемый объект, потому что его можно изменить без создания нового экземпляра.

  1. В больших приложениях его общий для струнных литералов занимает большие бит памяти. Таким образом, чтобы эффективно обрабатывать память, JVM выделяет область, называемую «String constant pool» ( обратите внимание, что в памяти даже неопубликованная String несет вокруг char [], int для своей длины, а другая для hash-кода. , напротив, требуется максимум восемь мгновенных байтов )
  2. Когда complier попадает в строковый литерал, он проверяет пул, чтобы увидеть, существует ли уже идентичный литерал. И если кто-то найден, ссылка на новый литерал направлена ​​на существующую строку, и новый «объект литерала струны» не создается (существующая строка просто получает дополнительную ссылку).
  3. Следовательно: String изменчивость сохраняет память …
  4. Но когда какая-либо переменная меняет значение, на самом деле – это только их ссылка, которая изменилась, а не значение в памяти (следовательно, это не повлияет на другие переменные, ссылающиеся на нее), как показано ниже ….

String s1 = “Старая строка”;

 //s1 variable, refers to string in memory reference | MEMORY | variables | | [s1] --------------->| "Old String" | 

Строка s2 = s1;

 //s2 refers to same string as s1 | | [s1] --------------->| "Old String" | [s2] ------------------------^ 

s1 = “Новая строка”;

 //s1 deletes reference to old string and points to the newly created one [s1] -----|--------->| "New String" | | | | |~~~~~~~~~X| "Old String" | [s2] ------------------------^ 

Исходная строка «в памяти» не изменилась, но ссылочная переменная была изменена так, что она ссылается на новую строку. И если бы у нас не было s2, «Old String» все равно будет в памяти, но мы не сможем получить к нему доступ …

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

 String foo = "Hello"; foo.substring(3); <-- foo here still has the same value "Hello" 

Чтобы сохранить изменения, вы должны сделать что-то вроде этого foo = foo.sustring (3);

Неизменяемый vs mutable может быть забавным, когда вы работаете с коллекциями. Подумайте, что произойдет, если вы используете изменяемый объект в качестве ключа для карты, а затем измените значение (подсказка: подумайте о equals и hashCode ).

Мне очень нравится объяснение от SCJP Sun Certified Programmer для Java 5 Study Guide .

Чтобы сделать Java более эффективной с точки зрения памяти, JVM выделяет специальную область памяти, называемую «String constant pool». Когда компилятор встречает строковый литерал, он проверяет пул, чтобы увидеть, существует ли идентичная строка. Если совпадение найдено, ссылка на новый литерал направлена ​​на существующую строку, и не создается новый объект литерала String.

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

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

  • Гораздо проще рассуждать о том, как работает ваша программа, когда вы знаете, что состояние объекта нельзя изменить другим способом
  • Неизменяемые объекты автоматически streamобезопасны (при условии, что они публикуются безопасно), поэтому никогда не станет причиной тех труднообратимых многопоточных ошибок
  • Неизменяемые объекты всегда будут иметь один и тот же код hashа, поэтому их можно использовать в качестве ключей в HashMap (или аналогичных). Если бы hash-код элемента в хеш-таблице изменился, запись таблицы была бы эффективно потеряна, так как попытки найти ее в таблице оказались бы в неправильном месте. Это основная причина, по которой объекты String неизменяемы – они часто используются в качестве ключей HashMap.

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

java.time

Это может быть немного поздно, но для того, чтобы понять, что является неизменным объектом, рассмотрите следующий пример из нового Java 8 Date and Time API ( java.time ). Поскольку вы, вероятно, знаете, что все объекты даты из Java 8 неизменяемы, поэтому в следующем примере

 LocalDate date = LocalDate.of(2014, 3, 18); date.plusYears(2); System.out.println(date); 

Вывод:

2014-03-18

Это печатает тот же год, что и начальная дата, потому что plusYears(2) возвращает новый объект, поэтому старая дата все еще остается неизменной, потому что это неизменный объект. После создания вы не можете его изменить, и переменная date все еще указывает на нее.

Итак, этот пример кода должен захватывать и использовать новый объект, созданный и возвращаемый этим вызовом plusYears .

 LocalDate date = LocalDate.of(2014, 3, 18); LocalDate dateAfterTwoYears = date.plusYears(2); 

date.toString () … 2014-03-18

dateAfterTwoYears.toString () … 2016-03-18

Одно значение имеет отношение к тому, как значение хранится на компьютере. Например, для строки .Net это означает, что строка в памяти не может быть изменена. Когда вы думаете, что меняете ее, вы на самом деле создаете новую string в памяти и указывая существующую переменную (которая является всего лишь указателем на фактический набор символов в другом месте) на новую строку.

После инстанцирования нельзя изменить. Рассмотрим class, в котором экземпляр может использоваться как ключ для hash-таблицы или аналогичного. Ознакомьтесь с практикой Java.

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

 String s1 = " abc "; String s2 = s1.trim(); 

В приведенном выше коде строка s1 не изменилась, другой объект ( s2 ) был создан с использованием s1 .

Что такое неизменяемый объект?

В соответствии с Java Reference Documentation «Объект считается неизменным, если его состояние не может измениться после его построения». Просто неизменяемый class – это class, свойства которого нельзя изменить после создания. Это означает, что при создании все данные экземпляра предоставляются и остаются неизменными до уничтожения объектов.

Почему неизменные объекты?

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

Обеспокоенность

Неизменяемые classы просты в проектировании, разработке и использовании, поскольку они более устойчивы к ошибкам и безопасности благодаря неизменности. Однако программисты неохотно используют их из-за ограничения на повторное использование. Кроме того, это может иметь влияние производительности на создание объекта, чем повторное использование. Однако с последними сложными компиляторами стоимость создания минимальна. Кроме того, предоставленные возможности и преимущество неизменности могут быть приняты за frameworks повторного использования в соответствии с потребностями.

Как работает приложение String?

Новый объект String создается с заданным значением, и ссылка обновляется до нового экземпляра, изолирующего старый объект.

Ссылка: http://www.devdummy.com/2017/09/immutable-objects-in-java.html

 String s1="Hi"; String s2=s1; s1="Bye"; System.out.println(s2); //Hi (if String was mutable output would be: Bye) System.out.println(s1); //Bye 

s1="Hi" : в нем был создан объект s1 со значением “Hi”.

s2=s1 : объект s2 создается со ссылкой на объект s1.

s1="Bye" : предыдущее значение объекта s1 не изменяется, поскольку s1 имеет тип String, а тип String – неизменяемый тип, вместо этого компилятор создает новый объект String со значением «Bye» и s1 на который он ссылается. здесь, когда мы печатаем значение s2 , результат будет «Hi» не «Bye», потому что s2 ссылается на предыдущий объект s1 который имел значение «Hi».

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

Рассмотрим приведенный ниже пример,

 class Testimmutablestring{ public static void main(String args[]){ String s="Future"; s.concat(" World");//concat() method appends the string at the end System.out.println(s);//will print Future because strings are immutable objects } } 

Давайте задумаемся, рассмотрим диаграмму ниже,

введите описание изображения здесь

На этой диаграмме вы можете увидеть новый объект, созданный как «Future World». Но не измените «Будущее». Because String is immutable . s , по-прежнему относятся к «Будущему». Если вам нужно позвонить в «Future World»,

 String s="Future"; s=s.concat(" World"); System.out.println(s);//print Future World 

Почему строковые объекты неизменяемы в java?

Поскольку Java использует концепцию строкового литерала. Предположим, что существует 5 ссылочных переменных, все относятся к одному объекту «Будущее». Если одна ссылочная переменная изменяет значение объекта, это будет зависеть от всех ссылочных переменных. Вот почему строковые объекты неизменяемы в java.

Неизменяемые объекты

Объект считается неизменным, если его состояние не может измениться после его построения. Максимальное использование неизменяемых объектов широко используется в качестве звуковой страtagsи для создания простого и надежного кода.

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

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

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

Источник

oracle docs говорит

Объект считается неизменным, если его состояние не может измениться после его построения. Максимальное использование неизменяемых объектов широко используется в качестве звуковой страtagsи для создания простого и надежного кода.

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

Мне нравится эта фраза с поста

Неизменяемые объекты упрощают параллельное программирование

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

Язык программирования AD, который становится все более популярным, имеет понятие «неизменности» через ключевое слово «инвариант». Проверьте эту статью доктора Добба об этом – http://dobbscodetalk.com/index.php?option=com_myblog&show=Invariant-Strings.html&Itemid=29 . Это прекрасно объясняет проблему.

  • Как выполнить команду для каждой строки файла?
  • Как определить, является ли строка числом?
  • Преобразование строки в байтовый массив в C #
  • В C, почему я не могу назначить строку массиву символов после ее объявления?
  • Пакет / Поиск и редактирование строк в TXT-файле
  • Как удалить разрывы строк из файла в Java?
  • Эквивалент Sprintf в Java
  • Когда использовать StringBuilder в Java
  • Разделить строку с точкой в ​​качестве разделителя
  • Найти строку текста в элементе и обернуть вокруг него tags span
  • Лучший способ заменить многие строки - обфускация в C #
  • Interesting Posts

    Как недавнее обнаружение столкновения SHA-1 влияет на Git?

    Как считать два разных столбца?

    iPhone SDK: как вы загружаете видеофайлы в Справочник документов, а затем воспроизводите их?

    Восстановление EFI Windows 8 после установки Ubuntu EFI

    Как реализовать одиночное наследование таблиц с помощью Larvel’s Eloquent?

    ‘свойство: 0’ или ‘свойство: 0px’ в CSS?

    Как передать объект из одного компонента в другой в Angular 2?

    Notepad ++: Как изменить клавишу Tab на другой ключ для вставки автозаполнения? Конфликт с другим плагином

    Как мне получить AppContext для выпуска компонентов AWT, чтобы они могли собирать мусор?

    Не удалось загрузить ресурс: net :: ERR_INSECURE_RESPONSE

    Запуск нового эмулятора Intel для Android

    Ошибка «ожидаемый тип параметра» в конструкторе общей структуры

    Как использовать инструменты для соавторов Office 2010?

    Текст центра Java в прямоугольнике

    Как читать и писать xml-файлы?

    Давайте будем гением компьютера.