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

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

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

376
задан Hearen 19 May 2019 в 04:39
поделиться

17 ответов

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

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

, например

class Foo
{
     private final String myvar;

     public Foo(final String initialValue)
     {
         this.myvar = initialValue;
     }

     public String getValue()
     {
         return this.myvar;
     }
}

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

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

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

255
ответ дан nbro 19 May 2019 в 04:39
поделиться

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

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

-1
ответ дан user36393 19 May 2019 в 04:39
поделиться

oracle docs сообщает

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

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

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

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

0
ответ дан yoAlex5 19 May 2019 в 04:39
поделиться

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

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

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

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

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

Источник

0
ответ дан Kamal Singh 19 May 2019 в 04:39
поделиться

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

2
ответ дан stjohnroe 19 May 2019 в 04:39
поделиться

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

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

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

3
ответ дан ROMANIA_engineer 19 May 2019 в 04:39
поделиться

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

5
ответ дан Charles Bretana 19 May 2019 в 04:39
поделиться

Мне очень нравится объяснение из SCJP Sun Certified Programmer for Java 5 Учебное пособие .

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

8
ответ дан wen 19 May 2019 в 04:39
поделиться
  1. В больших приложениях обычно строковые литералы занимают большие биты памяти. Таким образом, чтобы эффективно обрабатывать память, JVM выделяет область, называемую «Пул константных строк». ( Обратите внимание, что в памяти даже строка, на которую нет ссылок, несет вокруг char [], int для своей длины и другую для своего хэш-кода. Для числа, напротив, требуется максимум восемь непосредственных байтов )
  2. Когда complier встречается с литералом String, он проверяет пул, чтобы увидеть, существует ли уже идентичный литерал. И если он найден, ссылка на новый литерал направляется на существующую строку, и новый объект-литерал String не создается (существующая строка просто получает дополнительную ссылку).
  3. Следовательно: Изменяемость строк сохраняет память ...
  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, «Старая строка» все равно была бы в памяти, но у нас не было бы доступа к ней ...

24
ответ дан Community 19 May 2019 в 04:39
поделиться

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

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

Например, допустим, что у меня есть класс 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 называется изменяемой, поскольку вы можете изменить ( mutate) одно из его ключевых свойств без создания нового класса ColoredString. Причина, по которой это может быть плохо, например, допустим, у вас есть приложение с графическим интерфейсом, которое имеет несколько потоков, и вы используете ColoredStrings для печати данных в окне. Если у вас есть экземпляр ColoredString, который был создан как

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

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

blueString.setColor("Red");

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

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

24
ответ дан Jason Coco 19 May 2019 в 04:39
поделиться

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

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

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

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

31
ответ дан 19 May 2019 в 04:39
поделиться

java.time

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

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

Вывод:

2014-03-18

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

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

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

date.toString ()… 2014-03-18

dateAfterTwoYears.toString ()… 2016-03-18

13
ответ дан Basil Bourque 19 May 2019 в 04:39
поделиться

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

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

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

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

8
ответ дан Bill Michell 19 May 2019 в 04:39
поделиться
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, результатом будет «Привет», а не «Пока», потому что s2 ссылается на предыдущий объект s1, который имел значение «Привет».

4
ответ дан kokabi 19 May 2019 в 04:39
поделиться

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

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

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

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 был изменяемым (символы могли измениться позже), то вам пришлось бы скопируйте все символы, в противном случае изменения символов в подстроке будут отражены в другой строке позже.

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

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

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

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

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

Обе строки заменяют четвертый символ буквой «а». Второй фрагмент кода не только более читабелен, но и быстрее. Посмотрите, как вы должны сделать основной код для 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 является локальной ссылкой, у вас нет беспокоиться о безопасности параллелизма (только один поток когда-либо касается его). А поскольку на него больше нигде нет ссылок, он размещается только в стеке, поэтому он освобождается, как только завершается вызов функции (вам не нужно беспокоиться о сборке мусора). И вы получаете все преимущества производительности как изменчивости, так и неизменности.

79
ответ дан KNU 19 May 2019 в 04:39
поделиться

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

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

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

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

16
ответ дан ROMANIA_engineer 19 May 2019 в 04:39
поделиться

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

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

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

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

enter image description here

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

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

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

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

3
ответ дан Dev4World 19 May 2019 в 04:39
поделиться
Другие вопросы по тегам:

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