Правильно ли вызывать java.lang.String неизменяемым? - программирование
Подтвердить что ты не робот

Правильно ли вызывать java.lang.String неизменяемым?

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

java.lang.String имеет поле

/** Cache the hash code for the string */
private int hash; // Default to 0

который инициализируется при первом вызове метода hashCode(), поэтому он изменяется после создания:

    String s = new String(new char[] {' '});
    Field hash = s.getClass().getDeclaredField("hash");
    hash.setAccessible(true);
    System.out.println(hash.get(s));
    s.hashCode();
    System.out.println(hash.get(s));

Выход

0
32

Правильно ли вызывать String неизменяемым?

4b9b3361

Ответ 1

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

Я предлагаю прочитать Виды неизменности из блога Эрика Липперта. Хотя это технически статья С#, она весьма актуальна для поставленного вопроса. В частности:

Наблюдаемая неизменность:

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

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

Ответ 2

Лучшее определение будет не, что объект не изменится, но не может быть замечено, что оно было изменено. Это поведение никогда не изменится: .substring(x,y) всегда будет возвращать ту же самую вещь для этой строки для equals и всех других методов.

Эта переменная вычисляется при первом вызове .hashcode() и кэшируется для дальнейших вызовов. Это в основном то, что они называют "memoization" в языках функционального программирования.

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

Ответ 3

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

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

Ответ 4

Да, правильно назвать их неизменяемыми.

Хотя верно, что вы можете достичь и изменить переменные private... и final... класса, это ненужная и невероятно неразумная вещь для объекта String. Обычно считается, что никто не будет сумасшедшим, чтобы это сделать.

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

Также стоит отметить, что JLS утверждает, что использование отражения для изменения final может нарушить работу (например, в многопоточном режиме) или может не иметь никакого эффекта.

Ответ 5

С точки зрения разработчика, который использует отражение, он не корректен, чтобы называть String неизменяемым. Есть реальные Java-разработчики, которые используют рефлекс для ежедневного написания реального программного обеспечения. Отклонение отражения как "взлома" нелепо. Однако, с точки зрения разработчика, который не использует отражение, правильно называть String неизменяемым. Независимо от того, действительно ли предполагается, что String является неизменным, зависит от контекста.

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

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

Ответ 6

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

Ответ 7

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

Неизменяемость относится к изменениям, которые либо инициируются, либо воспринимаются приложением.

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

Ответ 8

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

Это неизменно по дизайну. Если вы используете Reflection (получение объявленного поля и сброс его доступности), вы обойдете его дизайн.

Ответ 9

Да, это правильно. Когда вы изменили строку, как в своем примере, создается новая String, но более старая сохраняет ее значение.