Co oznacza niezmienny?

400

To może być najgłupsze pytanie, jakie kiedykolwiek zadano, ale myślę, że jest to dość mylące dla początkującego Javy.

  1. Czy ktoś może wyjaśnić, co oznacza niezmienny ?
  2. Dlaczego jest Stringniezmienny?
  3. Jakie są zalety / wady niezmiennych obiektów?
  4. Dlaczego zmienny obiekt, taki jak StringBuilderpreferowany, zamiast String i vice-wers?

Dobry przykład (w Javie) zostanie naprawdę doceniony.

Ashokgelal
źródło
73
Widzisz, to nie było takie głupie pytanie. Cieszę się, że zapytałeś!
DOK
2
Nawiasem mówiąc, nie sądzę, że to najgłupsze pytanie w historii :) Myślę, że jest to bardzo ważna koncepcja do zrozumienia
Jason Coco,
1
Kiedy mówiłeś „StringBuilder”, czy nie miałeś na myśli modyfikowalnej klasy StringBuffer? String i StringBuffer są bardziej podobne w funkcji niż String i StringBuilder. StringBuffer jest w rzeczywistości zmiennym ciągiem.
Derek Mahar,
3
Czy mogę zasugerować dodanie tagu „początkujący” do tego pytania, aby programiści nowi w Javie mogli go znaleźć w poszukiwaniu innych pytań wprowadzających?
Derek Mahar,

Odpowiedzi:

268

Niezmienny oznacza, że ​​po zakończeniu wykonywania przez konstruktor obiektu nie można zmienić tego wystąpienia.

Jest to przydatne, ponieważ oznacza, że ​​możesz przekazywać odniesienia do obiektu w pobliżu, nie martwiąc się, że ktoś inny zmieni jego zawartość. Zwłaszcza w przypadku współbieżności nie występują problemy z blokowaniem obiektów, które nigdy się nie zmieniają

na przykład

class Foo
{
     private final String myvar;

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

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

Foonie musi się martwić, że osoba dzwoniąca getValue()może zmienić tekst w ciągu.

Jeśli wyobrażasz sobie klasę podobną do członka Foo, ale z członkiem, StringBuildera nie Stringczłonkiem, możesz zobaczyć, że osoba dzwoniąca getValue()może zmienić StringBuilderatrybut Fooinstancji.

Uważaj również na różne rodzaje niezmienności, które możesz znaleźć: Eric Lippert napisał na ten temat artykuł na blogu . Zasadniczo możesz mieć obiekty, których interfejs jest niezmienny, ale za kulisami rzeczywisty zmienny stan prywatny (i dlatego nie może być bezpiecznie dzielony między wątkami).

Douglas Leeder
źródło
3
Myślę, że powinieneś dodać jeden konstruktor arg, aby przypisać wartość przynajmniej raz. Punkt obecnego kodu nie jest jasny, ponieważ naprawdę nie ma wartości, którą można by zmienić :).
Georgy Bolyuba,
4
Powinieneś zrobić pole tylko do odczytu. To sprawia, że ​​jest całkowicie jasne, że pole jest niezmienne. W tej chwili jest niezmienny przez konwencję
JaredPar
7
Członek myVar powinien być ostateczny, aby było to naprawdę niezmienne.
laz
13
Masz rację, że myVar nie jest dostępny poza Foo. Jednak obecność finału wskazuje każdemu, kto może modyfikować klasę w przyszłości, że jej wartość nie powinna ulec zmianie. W takich okolicznościach wolę być tak wyraźny, jak to możliwe.
laz
2
A co powiesz na: „Typów referencyjnych nie można uczynić niezmiennymi tylko za pomocą ostatniego słowa kluczowego. Final tylko zapobiega zmianie przypisania”. from en.wikipedia.org/wiki/Immutable_object
Yousha Aleayoub
81

Niezmienny obiekt to obiekt, w którym pola wewnętrzne (lub przynajmniej wszystkie pola wewnętrzne, które wpływają na jego zachowanie zewnętrzne) nie mogą zostać zmienione.

Niezmienne łańcuchy mają wiele zalet:

Wydajność: wykonaj następującą operację:

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

Podstawowy C dla metody substring () jest prawdopodobnie mniej więcej taki:

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

Pamiętaj, że nie trzeba kopiować żadnych znaków! Gdyby obiekt String był modyfikowalny (znaki mogłyby się później zmienić), musiałbyś skopiować wszystkie znaki, w przeciwnym razie zmiany znaków w podciągu zostaną odzwierciedlone w innym ciągu później.

Współbieżność: Jeśli wewnętrzna struktura niezmiennego obiektu jest poprawna, zawsze będzie poprawna. Nie ma szans, że różne wątki mogą stworzyć nieprawidłowy stan w tym obiekcie. Dlatego niezmienne obiekty są bezpieczne dla wątków .

Odśmiecanie: Śmieciarka znacznie łatwiej podejmuje logiczne decyzje dotyczące niezmiennych obiektów.

Istnieją jednak również wady niezmienności:

Wydajność: Zaczekaj, myślałem, że powiedziałeś, że wydajność jest zaletą niezmienności! Czasami tak jest, ale nie zawsze. Weź następujący kod:

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

Obie linie zastępują czwarty znak literą „a”. Drugi fragment kodu jest nie tylko bardziej czytelny, ale także szybszy. Zobacz, jak będziesz musiał wykonać podstawowy kod dla foo. Podciągi są łatwe, ale teraz, ponieważ w polu piątym jest już znak i coś innego może odnosić się do foo, nie możesz go po prostu zmienić; musisz skopiować cały ciąg znaków (oczywiście niektóre z tych funkcji są wyodrębnione do funkcji w prawdziwym bazowym C, ale chodzi tutaj o pokazanie kodu, który zostanie wykonany w jednym miejscu).

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

Zauważ, że konkatenat jest wywoływany dwukrotnie, co oznacza, że ​​cały łańcuch musi być zapętlony! Porównaj to z kodem C baroperacji:

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

Zmienna operacja na łańcuchach jest oczywiście znacznie szybsza.

Podsumowując: W większości przypadków potrzebujesz niezmiennego ciągu. Ale jeśli musisz dużo dodawać i wstawiać do łańcucha, potrzebujesz zmienności prędkości. Jeśli chcesz mieć korzyści z bezpieczeństwa współbieżności i odśmiecania, kluczem jest utrzymanie zmiennych obiektów w pobliżu metody:

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

Ponieważ mutableobiekt jest lokalnym odwołaniem, nie musisz się martwić o bezpieczeństwo współbieżności (tylko jeden wątek go dotyka). Ponieważ nigdzie indziej nie jest tam przywoływany, jest przydzielany tylko na stosie, więc jest on zwalniany natychmiast po zakończeniu wywołania funkcji (nie musisz się martwić o odśmiecanie). I zyskujesz wszystkie zalety wydajności, zarówno zmienności, jak i niezmienności.

Imagist
źródło
4
Świetna lektura! myślę tylko, że powinno być, jeśli (pierwszy), a nie jeśli (! pierwszy)
Siddhartha
Konieczne jest nie to, aby pola były niezmienne, ale raczej, aby określony obserwowalny stan obiektu był niezmienny; obiekt, który zawiera odniesienie do innego obiektu jako środek do kapsułkowania stanu w nim zawartego, może być niezmienny tylko wtedy, gdy wszystkie kapsułkowane aspekty stanu, które wystawia na świat zewnętrzny, są również niezmienne. Zauważ, że pola nie są ani konieczne, ani wystarczające, aby pola były niezmiennych typów. Liczy się stan widoczny.
supercat
7
Passing pointers because Java is pass-by-referenceCzy Java nie jest „wartością przekazywaną?”
Cristian Gutu
@CristianGutu tak masz rację JAVA to „Pass by Value” a nie „Pass by REFERENCE”
Arsh Kaushal
Odniesienie jest przekazywane jako wartość !!
devv 15.01.19
31

W rzeczywistości String nie jest niezmienny, jeśli użyjesz sugerowanej powyżej definicji wikipedia.

Stan ciągu zmienia się po konstrukcji. Spójrz na metodę hashcode (). Łańcuch buforuje wartość hashcode w polu lokalnym, ale nie oblicza jej aż do pierwszego wywołania hashcode (). Ta leniwa ocena hashcode umieszcza String w interesującej pozycji jako niezmienny obiekt, którego stan zmienia się, ale nie można zaobserwować, że zmienił się bez użycia odbicia.

Może więc definicja niezmienności powinna być obiektem, którego zmiany nie można zaobserwować.

Jeśli stan zmienia się w obiekcie niezmiennym po jego utworzeniu, ale nikt go nie widzi (bez odbicia), czy obiekt nadal jest niezmienny?


źródło
1
Dobry pomysł - nie można zaobserwować, że obiekt się zmienił, a także nie ma możliwości, aby zmienić go z zewnątrz. Pole prywatne dla hashCode () to wewnętrzna zmiana, która nie jest istotna dla widocznego z zewnątrz stanu obiektu.
mparaz
2
W rzeczywistości można zauważyć, że zmieniło się, jeśli używasz odbicia. Zobacz więcej na Sedgewick's Strings są zmienne, jeśli pozwolisz na refleksję .
Miguel
24

Niezmienne obiekty to obiekty, których nie można zmienić programowo. Są szczególnie dobre w środowiskach wielowątkowych lub innych środowiskach, w których więcej niż jeden proces może zmieniać (mutować) wartości w obiekcie.

Jednak dla wyjaśnienia StringBuilder jest w rzeczywistości obiektem zmiennym, a nie niezmiennym. Zwykły ciąg java jest niezmienny (co oznacza, że ​​po utworzeniu nie można zmienić leżącego pod nim łańcucha bez zmiany obiektu).

Załóżmy na przykład, że mam klasę o nazwie ColoredString, która ma wartość String i kolor 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;
    }

}

W tym przykładzie mówi się, że ColoredString jest zmienny, ponieważ można zmienić (mutować) jedną z jego kluczowych właściwości bez tworzenia nowej klasy ColoredString. Przyczyną tego może być na przykład założenie, że masz aplikację GUI, która ma wiele wątków i używasz aplikacji ColorfulStrings do drukowania danych w oknie. Jeśli masz instancję ColouredString, która została utworzona jako

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

Wtedy można oczekiwać, że ciąg będzie zawsze „niebieski”. Jeśli jednak inny wątek dostanie tę instancję i zadzwoni

blueString.setColor("Red");

Nagle, i prawdopodobnie nieoczekiwanie, miałbyś teraz „czerwony” sznur, kiedy chciałeś „niebieski”. Z tego powodu niezmienne obiekty są prawie zawsze preferowane przy przekazywaniu instancji obiektów dookoła. Kiedy masz przypadek, w którym zmienne obiekty są naprawdę konieczne, wtedy zwykle chronisz objet, przekazując tylko kopie z określonego pola kontroli.

Podsumowując, w Javie java.lang.String jest niezmiennym obiektem (nie można go zmienić po utworzeniu), a java.lang.StringBuilder jest obiektem zmiennym, ponieważ można go zmienić bez tworzenia nowej instancji.

Jason Coco
źródło
Powinieneś zrobić pola tylko do odczytu. W tej chwili twoja klasa jest niezmienna przez konwencję. Nie ma żadnych wskazówek dla przyszłych programistów, że niezmienne jest zamierzone. Czytanie pól tylko do wyjaśnienia pomoże ci wyjaśnić zamiar przyszłego programisty
JaredPar
@JaredPar - W rzeczywistości klasa nie jest niezmienna ... jest to przykład klasy, którą można modyfikować, aby pokazać, dlaczego może to stanowić problem.
Jason Coco,
1
@JaredPar - Och, to całkowicie w porządku :) Chciałem napisać to nieco lepiej, ale Douglas jest już dobrze napisany i wydaje się być ulubionym, więc zostawię mój jako kolejny przykład; ale ktoś tak naprawdę go zmodyfikował, aby właściwości były ostateczne, co moim zdaniem było zabawne :)
Jason Coco,
24
  1. W dużych aplikacjach literały łańcuchowe często zajmują duże ilości pamięci. Aby więc skutecznie obsługiwać pamięć, JVM przydziela obszar o nazwie „Ciągła pula ciągów znaków” (należy zauważyć, że w pamięci nawet niepowiązany ciąg znaków przenosi wokół znaku char [], liczby całkowitej dla jej długości, a drugiej dla swojego kodu skrótu. Dla liczby , przeciwnie, wymagane jest maksymalnie osiem bezpośrednich bajtów )
  2. Gdy kompilator natrafi na literał łańcuchowy, sprawdza pulę, aby sprawdzić, czy istnieje już identyczny literał. A jeśli taki zostanie znaleziony, odniesienie do nowego literału jest kierowane do istniejącego ciągu znaków i nie jest tworzony żaden nowy „obiekt literału łańcucha znaków” (istniejący ciąg znaków otrzymuje po prostu dodatkowe odniesienie).
  3. Stąd: zmienność łańcuchów oszczędza pamięć ...
  4. Ale kiedy którakolwiek ze zmiennych zmienia wartość, w rzeczywistości - zmienia się tylko ich odwołanie, a nie wartość w pamięci (stąd nie wpłynie to na inne zmienne, do których się odwołuje), jak pokazano poniżej ...

Ciąg s1 = „Stary ciąg”;

//s1 variable, refers to string in memory
        reference                 |     MEMORY       |
        variables                 |                  |

           [s1]   --------------->|   "Old String"   |

Ciąg s2 = s1;

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

s1 = „Nowy ciąg”;

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

Oryginalny ciąg „w pamięci” nie zmienił się, ale zmienna referencyjna została zmieniona, tak aby odnosiła się do nowego ciągu. A gdybyśmy nie mieli s2, „Stary ciąg” nadal byłby w pamięci, ale nie będziemy mogli uzyskać do niego dostępu ...

Shanaka Jayalath
źródło
16

„niezmienny” oznacza, że ​​nie można zmienić wartości. Jeśli masz instancję klasy String, każda wywoływana metoda, która wydaje się modyfikować wartość, faktycznie utworzy inny ciąg.

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

Aby zachować zmiany, powinieneś zrobić coś takiego: foo = foo.sustring (3);

Niezmienne kontra zmienne mogą być zabawne podczas pracy z kolekcjami. Zastanów się, co się stanie, jeśli użyjesz zmiennego obiektu jako klucza do mapy, a następnie zmienisz wartość (wskazówka: pomyśl o equalsi hashCode).

Georgy Bolyuba
źródło
13

java.time

Może być trochę za późno, ale aby zrozumieć, czym jest niezmienny obiekt, rozważ następujący przykład z nowego interfejsu API daty i godziny Java 8 ( java.time ). Jak zapewne wiesz, wszystkie obiekty daty z Java 8 są niezmienne, więc w poniższym przykładzie

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

Wynik:

2014-03-18

Zostanie wydrukowany ten sam rok, co data początkowa, ponieważ plusYears(2)zwraca nowy obiekt, więc stara data pozostaje niezmieniona, ponieważ jest to obiekt niezmienny. Po utworzeniu nie można go dalej modyfikować, a zmienna daty nadal wskazuje na to.

Tak więc ten przykład kodu powinien przechwycić i użyć nowego obiektu utworzonego i zwróconego przez to wywołanie plusYears.

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

date.toString ()… 18.03.2014

dateAfterTwoYears.toString ()… 18.03.2016

Jerzy
źródło
8

Naprawdę podoba mi się wyjaśnienie SCJP Sun Certified Programmer for Java 5 Study Guide .

Aby Java była bardziej wydajna, JVM odkłada specjalny obszar pamięci zwany „pulą stałych ciągów”. Gdy kompilator napotka literał ciągu znaków, sprawdza pulę, aby sprawdzić, czy identyczny ciąg znaków już istnieje. Jeśli zostanie znalezione dopasowanie, odwołanie do nowego literału jest kierowane do istniejącego ciągu znaków i nie jest tworzony żaden nowy obiekt literału ciągu.

wen
źródło
Powinno być w stanie to zrobić z dowolnymi identycznymi niezmiennymi obiektami, ale przypuszczam, że zajęłoby to zbyt wiele czasu działania.
Zan Lynx,
8

Obiekty, które są niezmienne, nie mogą zmienić swojego stanu po ich utworzeniu.

Istnieją trzy główne powody używania niezmiennych obiektów, gdy tylko możesz, wszystkie z nich pomogą zmniejszyć liczbę błędów, które wprowadzasz w kodzie:

  • O wiele łatwiej jest zrozumieć sposób działania programu, gdy wiadomo, że stanu obiektu nie można zmienić inną metodą
  • Niezmienne obiekty są automatycznie bezpieczne dla wątków (zakładając, że są bezpiecznie publikowane), więc nigdy nie będą przyczyną tych trudnych do ustalenia błędów wielowątkowych
  • Niezmienne obiekty zawsze będą miały ten sam kod Hash, więc mogą być używane jako klucze w HashMap (lub podobnym). Jeśli kod skrótu elementu w tablicy skrótów miałby ulec zmianie, pozycja tabeli zostałaby wówczas skutecznie utracona, ponieważ próby znalezienia go w tabeli skończyłyby się w niewłaściwym miejscu. Jest to główny powód, dla którego obiekty String są niezmienne - często są używane jako klucze HashMap.

Istnieją również inne optymalizacje, które możesz wykonać w kodzie, gdy wiesz, że stan obiektu jest niezmienny - na przykład buforowanie obliczonego skrótu - ale są to optymalizacje i dlatego nie są tak interesujące.

Bill Michell
źródło
5

Jedno znaczenie ma związek ze sposobem przechowywania wartości na komputerze. Na przykład ciąg .Net oznacza, że ​​nie można zmienić ciągu w pamięci. Gdy myślisz, że go zmieniasz, w rzeczywistości tworzysz nowy łańcuch w pamięci i wskazujący istniejącą zmienną (która jest tylko wskaźnikiem do faktycznej kolekcji znaków gdzie indziej) na nowy ciąg.

Charles Bretana
źródło
4
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": obiekt s1został utworzony z wartością „Cześć”.

s2=s1 : obiekt s2jest tworzony w odniesieniu do obiektu s1.

s1="Bye": wartość poprzedniego s1obiektu nie zmienia się, ponieważ s1ma typ String, a typ String jest niezmiennym typem, zamiast tego kompilator tworzy nowy obiekt String z wartością „Bye” i s1odnosi się do niego. tutaj, gdy wypisujemy s2wartość, wynikiem będzie „Cześć”, a nie „Cześć”, ponieważ s2odnosi się do poprzedniego s1obiektu, który miał wartość „Cześć”.

kokabi
źródło
czy możesz dodać trochę wyjaśnienia?
minigeek
3

Niezmienny oznacza, że ​​po utworzeniu obiektu żaden z jego członków się nie zmieni. Stringjest niezmienny, ponieważ nie można zmienić jego zawartości. Na przykład:

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

W powyższym kodzie ciąg s1 nie zmienił się, s2utworzono inny obiekt ( ) przy użyciu s1.

eishay
źródło
3

Niezmienne oznacza po prostu niezmienne lub niemodyfikowalne. Po utworzeniu obiektu łańcuchowego nie można zmienić jego danych ani stanu

Rozważ poniższy przykład,

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

Pomyślmy o poniższym schemacie,

wprowadź opis zdjęcia tutaj

Na tym schemacie widać nowy obiekt utworzony jako „Future World”. Ale nie zmieniaj „Przyszłości”. Because String is immutable. s, nadal odnoszą się do „Przyszłości”. Jeśli chcesz zadzwonić do „Future World”,

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

Dlaczego obiekty łańcuchowe są niezmienne w Javie?

Ponieważ Java używa pojęcia literału łańcuchowego. Załóżmy, że istnieje 5 zmiennych referencyjnych, wszystkie odnoszą się do jednego obiektu „Przyszłość”. Jeśli jedna zmienna referencyjna zmienia wartość obiektu, wpłynie to na wszystkie zmienne referencyjne. Dlatego obiekty łańcuchowe są niezmienne w Javie.

JustCode
źródło
2

Po utworzeniu nie można go zmienić. Rozważ klasę, której wystąpienie może być użyte jako klucz do tablicy mieszającej lub podobnej. Sprawdź najlepsze praktyki Java.

stjohnroe
źródło
0

Niezmienne przedmioty

Obiekt uważa się za niezmienny, jeśli jego stan nie może się zmienić po jego zbudowaniu. Maksymalne poleganie na niezmiennych obiektach jest powszechnie akceptowane jako rozsądna strategia tworzenia prostego, niezawodnego kodu.

Niezmienne obiekty są szczególnie przydatne w aplikacjach współbieżnych. Ponieważ nie mogą zmienić stanu, nie mogą zostać uszkodzone przez interferencję nici ani zaobserwowane w niespójnym stanie.

Programiści często niechętnie stosują niezmienne obiekty, ponieważ martwią się kosztami stworzenia nowego obiektu, a nie jego aktualizacją. Wpływ tworzenia obiektów jest często przeceniany i można go zrównoważyć niektórymi korzyściami związanymi z niezmiennymi obiektami. Należą do nich zmniejszone obciążenie z powodu wyrzucania elementów bezużytecznych i eliminacja kodu potrzebnego do ochrony obiektów zmiennych przed uszkodzeniem.

Poniższe podrozdziały biorą klasę, której instancje są zmienne i wywodzą z niej klasę z instancjami niezmiennymi. W ten sposób podają ogólne zasady tego rodzaju konwersji i pokazują niektóre zalety niezmiennych obiektów.

Źródło

Kamal Singh
źródło
0

Ponieważ zaakceptowana odpowiedź nie odpowiada na wszystkie pytania. Jestem zmuszony udzielić odpowiedzi po 11 latach i 6 miesiącach.

Czy ktoś może wyjaśnić, co oznacza niezmienny?

Mam nadzieję, że miałeś na myśli nieruchomy obiekt (ponieważ moglibyśmy pomyśleć o niezmiennym odwołaniu ).

Obiekt jest niezmienny : po utworzeniu iff zawsze reprezentują tę samą wartość (nie ma żadnej metody zmieniającej wartość).

Dlaczego jest Stringniezmienny?

Przestrzegaj powyższej definicji, którą można sprawdzić, sprawdzając kod źródłowy Sting.java .

Jakie są zalety / wady niezmiennych obiektów? niezmienne typy to:

  • bezpieczniejsze od błędów.

  • łatwiejsze do zrozumienia.

  • i bardziej gotowi na zmiany.

Dlaczego zmienny obiekt, taki jak StringBuilder, powinien być lepszy od String i vice-verse?

Zawężenie pytania Dlaczego potrzebujemy zmiennego StringBuilder w programowaniu? Typowym zastosowaniem jest łączenie dużej liczby ciągów razem, jak poniżej:

String s = "";
for (int i = 0; i < n; ++i) {
    s = s + n;
}

Używając niezmiennych ciągów, tworzy się wiele tymczasowych kopii - pierwsza liczba ciągu („0”) jest faktycznie kopiowana n razy w trakcie budowania końcowego ciągu, druga liczba jest kopiowana n-1 razy, i tak na. Faktycznie kosztuje O (n2) czas na zrobienie całego tego kopiowania, nawet jeśli połączymy tylko n elementów.

StringBuilder został zaprojektowany w celu zminimalizowania tego kopiowania. Wykorzystuje prostą, ale sprytną wewnętrzną strukturę danych, aby w ogóle uniknąć kopiowania do samego końca, gdy poprosisz o końcowy ciąg znaków za pomocą wywołania toString ():

StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; ++i) {
  sb.append(String.valueOf(n));
}
String s = sb.toString();

Uzyskanie dobrej wydajności jest jednym z powodów, dla których korzystamy ze zmiennych obiektów. Kolejnym jest wygodne udostępnianie: dwie części twojego programu mogą komunikować się wygodniej, dzieląc wspólną zmienną strukturę danych.

Więcej można znaleźć tutaj: https://web.mit.edu/6.005/www/fa15/classes/09-immutability/#useful_immutable_types

Chulo
źródło
-1

Niezmienny obiekt to taki, którego nie można zmodyfikować po jego utworzeniu. Typowym przykładem są literały łańcuchowe.

Język programowania AD, który staje się coraz bardziej popularny, ma pojęcie „niezmienność” poprzez słowo kluczowe „niezmiennik”. Sprawdź artykuł Dr.Dobb na ten temat - http://dobbscodetalk.com/index.php?option=com_myblog&show=Invariant-Strings.html&Itemid=29 . Doskonale wyjaśnia problem.

użytkownik36393
źródło
Wierzę, że od D 2.020 słowo kluczowe zostało zmienione z niezmiennego na niezmienne. Nie widzę sensu, ale mówi: „niezmienne teraz jest zaimplementowane”. digitalmars.com/d/2.0/changelog.html#new2_020
he_the_great