Почему строки не могут быть изменяемыми в Java и .NET? - PullRequest
185 голосов
/ 18 сентября 2008

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

Ответы [ 17 ]

3 голосов
/ 08 мая 2009

Для большинства целей «строка» - это (используется / рассматривается как / считается / считается) значимая атомная единица, , как и число .

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

Ты должен знать почему. Просто подумай об этом.

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

Мы выполняем вычисления и сравнения с «строками», аналогично тому, как мы делаем с числами. Если бы строки (или целые числа) были изменяемыми, нам пришлось бы написать специальный код, чтобы зафиксировать их значения в неизменяемых локальных формах для надежного выполнения любого вида вычислений. Поэтому лучше думать о строке как о числовом идентификаторе, но вместо длины в 16, 32 или 64 бита она может быть длиной в сотни бит.

Когда кто-то говорит «струна», мы все думаем о разных вещах. Те, кто думает об этом просто как о наборе персонажей, не имея особой цели, конечно же, будут потрясены тем, что кто-то только что решил , что он не сможет манипулировать этими персонажами. Но класс "string" - это не просто массив символов. Это STRING, а не char[]. Существуют некоторые основные предположения о концепции, которую мы называем «строкой», и ее обычно можно описать как значимую атомарную единицу кодированных данных, например число. Когда люди говорят о «манипулировании строками», возможно, они действительно говорят о манипулировании символами для создания строк , и StringBuilder отлично подходит для этого. Подумайте немного о том, что на самом деле означает слово «строка».

Подумайте на мгновение, что было бы, если бы строки были изменяемыми. Следующая функция API может быть обманута для возврата информации для другого пользователя, если строка имени пользователя mutable преднамеренно или непреднамеренно изменена другим потоком, когда эта функция использует ее:

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 );
    }
}

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

2 голосов
/ 20 марта 2009

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

2 голосов
/ 18 сентября 2008

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

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

2 голосов
/ 16 декабря 2008

Решение иметь изменяемую строку в C ++ вызывает много проблем, см. Эту превосходную статью Келвина Хенни о Mad COW Disease .

COW = Копировать при записи.

0 голосов
/ 02 ноября 2013

Почти для каждого правила есть исключение:

using System;
using System.Runtime.InteropServices;

namespace Guess
{
    class Program
    {
        static void Main(string[] args)
        {
            const string str = "ABC";

            Console.WriteLine(str);
            Console.WriteLine(str.GetHashCode());

            var handle = GCHandle.Alloc(str, GCHandleType.Pinned);

            try
            {
                Marshal.WriteInt16(handle.AddrOfPinnedObject(), 4, 'Z');

                Console.WriteLine(str);
                Console.WriteLine(str.GetHashCode());
            }
            finally
            {
                handle.Free();
            }
        }
    }
}
0 голосов
/ 18 сентября 2008

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

0 голосов
/ 18 сентября 2008

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

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