Почему строки не могут быть изменяемыми в Java и.NET?

Почему случается так, что они решили сделать String неизменный в Java и.NET (и некоторые другие языки)? Почему они не сделали это изменяемым?

189
задан deHaar 12 September 2019 в 11:02
поделиться

14 ответов

Согласно Эффективный Java, глава 4, страница 73, 2-й выпуск:

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

[...]

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

[...]

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

[...]

Другие маленькие точки из той же главы:

Не только может Вы совместно использовать неизменные объекты, но и можно совместно использовать их внутренности.

[...]

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

[...]

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

203
ответ дан dantiston 23 November 2019 в 05:39
поделиться

Неизменность хороша. Посмотрите Эффективный Java. Если бы необходимо было скопировать Строку каждый раз, когда Вы раздали ее, то это было бы большим количеством подверженного ошибкам кода. У Вас также есть беспорядок относительно который влияние модификаций который ссылки. Таким же образом то Целое число должно быть неизменным для поведения как интервал, Строки должны вести себя как неизменные для действия как примитивы. В строках передачи C++ значением делает это без явного упоминания в исходном коде.

0
ответ дан Tom Hawtin - tackline 23 November 2019 в 05:39
поделиться

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

-1
ответ дан deHaar 23 November 2019 в 05:39
поделиться

Строки в Java не действительно неизменны, можно изменить отражение использования их значения и или загрузка класса. Вы не должны быть в зависимости от того свойства для безопасности. Поскольку примеры видят: Волшебный Прием В Java

2
ответ дан deHaar 23 November 2019 в 05:39
поделиться

Решение иметь строку, изменяемую в C++, вызывает много проблем, см. эту превосходную статью Kelvin Henney [приблизительно 110] Коровье бешенство .

COW = Копия На Записи.

2
ответ дан Motti 23 November 2019 в 05:39
поделиться

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

оборотная сторона - то, что конкатенации делают много дополнительных строк, которые являются только переходными и просто становятся мусором, на самом деле вредя производительности памяти. У Вас есть StringBuffer и StringBuilder (в Java, StringBuilder находится также в.NET) использовать для сохранения памяти в этих случаях.

2
ответ дан deHaar 23 November 2019 в 05:39
поделиться

Строка не является типом примитива, все же Вы обычно хотите использовать ее с семантикой значения, т.е. как значение.

значение А - что-то, чему можно доверять, не изменится за спиной. Если Вы пишете: String str = someExpr(); Вы не хотите, чтобы он изменился, если ВЫ не делаете что-то с str.

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

7
ответ дан deHaar 23 November 2019 в 05:39
поделиться

Нужно действительно спросить, "почему X должно быть изменяемым?" Лучше принять значение по умолчанию к неизменности из-за преимуществ, уже упомянутых принцесса Fluff . Это должно быть исключение, что что-то изменяемо.

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

11
ответ дан Community 23 November 2019 в 05:39
поделиться

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

7
ответ дан deHaar 23 November 2019 в 05:39
поделиться

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

28
ответ дан Matt Howells 23 November 2019 в 05:39
поделиться

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

Безопасность Thead:

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

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

Производительность:

, В то время как Строковое интернирование было упомянуто, оно только представляет маленькое усиление в эффективности памяти для программ Java. Только строковые литералы интернируются. Это означает, что только строки, которые являются тем же в Вашем исходный код , совместно используют тот же Строковый Объект. Если Ваша программа динамично создаст строку, которые являются тем же, то они будут представлены в различных объектах.

, Что еще более важно, неизменные строки позволяют им совместно использовать свои внутренние данные. Для многих строковых операций это означает, что основной массив символов не должен быть скопирован. Например, скажите, что Вы хотите взять пять первых символов Строки. В Java Вы были бы вызовы myString.substring (0,5). В этом случае, что подстрока (), который делает метод, должна просто создать новую Строку, возражают, что myString's долей, лежащий в основе символа [], но кто знает, что это запускается в индексе 0 и концах в индексе 5 того символа []. Для помещения этого в графическую форму Вы закончили бы со следующим:

 |               myString                  |
 v                                         v
"The quick brown fox jumps over the lazy dog"   <-- shared char[]
 ^   ^
 |   |  myString.substring(0,5)

Это делает этот вид из операций чрезвычайно дешевым, и O (1) начиная с операции ни зависит от длины исходной строки, ни на длине подстроки, которую мы должны извлечь. Это поведение также обладает некоторыми преимуществами памяти, так как много строк могут совместно использовать свой базовый символ [].

57
ответ дан LordOfThePigs 23 November 2019 в 05:39
поделиться

Существует по крайней мере две причины.

Первый - безопасность http://www.javafaq.nu/java-article1060.html

главная причина, почему Строка, сделанная неизменной, была безопасностью. Посмотрите на этот пример: у Нас есть файл открытый метод с проверкой входа в систему. Мы передаем Строку этому методу для обработки аутентификации, которая необходима, прежде чем вызов будет передан ОС. Если Строка была изменяема, было возможно так или иначе изменить свое содержание после проверки аутентификации, прежде чем ОС получит запрос из программы тогда, возможно запросить любой файл. Таким образом, если Вы имеете право открыть текстовый файл в пользовательском каталоге, но тогда на лету, когда так или иначе Вам удается изменить имя файла, можно запросить открыть "passwd" файл или любого другого. Тогда файл может быть изменен, и будет возможно войти в систему непосредственно к ОС.

1110-секундный - эффективность Памяти http://hikrish.blogspot.com/2006/07/why-string-class-is-immutable.html

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

102
ответ дан Jorge Ferreira 23 November 2019 в 05:39
поделиться

Ничего себе! Я не Могу верить дезинформации здесь. Strings быть неизменным ничего не имеют с безопасностью. Если бы у кого-то уже есть доступ к объектам в запущенном приложении (который должен был бы быть принят, при попытке принять меры против кого-то 'взламывающего' a String в Вашем приложении), они, конечно, были бы большим количеством других возможностей, доступных для взламывания.

Это - довольно свежая идея что неизменность String решает проблемы поточной обработки. Хм... У меня есть объект, который изменяется двумя различными потоками. Как я разрешаю это? синхронизировать доступ к объекту? Naawww... позволяют нам не позволенный любой изменить объект вообще - это устранит все наши грязные проблемы параллелизма! На самом деле давайте сделаем все объекты неизменными, и затем мы можем, удалил конструкцию synchonized из языка Java.

Настоящая причина (указанный другими выше) является оптимизацией памяти. Довольно распространено в любом приложении для того же строкового литерала использоваться неоднократно. Столь распространено, на самом деле, что несколько десятилетий назад, много компиляторов сделали оптимизацию из хранения только единственного экземпляра a String литерал. Недостаток этой оптимизации состоит в том, что код во время выполнения, который изменяет a String литерал представляет проблему, потому что он изменяет экземпляр для всего другого кода, который совместно использует его. Например, для функции где-нибудь в приложении было бы не хорошо измениться String литерал "dog" кому: "cat". A printf("dog") привел бы к "cat" быть записанным в stdout. По этой причине должен был быть способ принять меры против кода, который пытается измениться String литералы (т.е., сделайте их неизменными). Некоторые компиляторы (при поддержке ОС) выполнили бы это путем размещения String литерал в специальный сегмент постоянной памяти, который вызвал бы отказ памяти, если бы попытка записи была предпринята.

В Java это известно как интернирование. Компилятор Java здесь просто следует за стандартной оптимизацией памяти, сделанной компиляторами в течение многих десятилетий. И решать ту же проблему их String литералы, изменяемые во времени выполнения, Java просто делает String неизменный класс (т.е., не дает Вам методов set, которые позволили бы Вам изменяться String содержание). Strings не должен был бы быть неизменным при интернировании String литералы не произошли.

7
ответ дан deHaar 23 November 2019 в 05:39
поделиться

For most purposes, a "string" is (used/treated as/thought of/assumed to be) a meaningful atomic unit, just like a number.

Asking why the individual characters of a string are not mutable is therefore like asking why the individual bits of an integer are not mutable.

You should know why. Just think about it.

I hate to say it, but unfortunately we're debating this because our language sucks, and we're trying to using a single word, string, to describe a complex, contextually situated concept or class of object.

We perform calculations and comparisons with "strings" similar to how we do with numbers. If strings (or integers) were mutable, we'd have to write special code to lock their values into immutable local forms in order to perform any kind of calculation reliably. Therefore, it is best to think of a string like a numeric identifier, but instead of being 16, 32, or 64 bits long, it could be hundreds of bits long.

When someone says "string", we all think of different things. Those who think of it simply as a set of characters, with no particular purpose in mind, will of course be appalled that someone just decided that they should not be able to manipulate those characters. But the "string" class isn't just an array of characters. It's a STRING, not a char[]. There are some basic assumptions about the concept we refer to as a "string", and it generally can be described as meaningful, atomic unit of coded data like a number. When people talk about "manipulating strings", perhaps they're really talking about manipulating characters to build strings, and a StringBuilder is great for that. Just think a bit about what the word "string" truly means.

Consider for a moment what it would be like if strings were mutable. The following API function could be tricked into returning information for a different user if the mutable username string is intentionally or unintentionally modified by another thread while this function is using it:

string GetPersonalInfo( string username, string password )
{
    string stored_password = DBQuery.GetPasswordFor( username );
    if (password == stored_password)
    {
        //another thread modifies the mutable 'username' string
        return DBQuery.GetPersonalInfoFor( username );
    }
}

Security isn't just about 'access control', it's also about 'safety' and 'guaranteeing correctness'. If a method can't be easily written and depended upon to perform a simple calculation or comparison reliably, then it's not safe to call it, but it would be safe to call into question the programming language itself.

3
ответ дан 23 November 2019 в 05:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: