불변이란 무엇입니까?


400

이것은 가장 까다로운 질문 일 수 있지만 Java 초보자에게는 혼란 스럽다고 생각합니다.

  1. 누군가 불변의 의미를 명확히 할 수 있습니까? ?
  2. String 불변인가?
  3. 불변 개체의 장점 / 단점은 무엇입니까?
  4. StringBuilderString과 그 반대의 변경 가능한 객체를 선호 해야 합니까?

좋은 예 (자바)는 정말 감사하겠습니다.


73
멍청한 질문이 아니 었습니다. 다행이다!
DOK

2
그런데, 나는 이제까지 : 나는 그것을 이해하는 매우 중요한 개념이라고 생각 그것이 멍청한 질문이라고 생각하지 않는다
제이슨 코코

1
StringBuilder를 말할 때 가변 클래스 StringBuffer를 의미하지 않습니까? String 및 StringBuffer는 String 및 StringBuilder보다 기능면에서 더 유사합니다. StringBuffer는 사실상 변경 가능한 문자열입니다.
Derek Mahar

3
Java에 익숙하지 않은 프로그래머가 다른 입문 질문을 검색 할 수 있도록이 질문에 "초보자"태그를 추가 할 것을 제안 할 수 있습니까?
Derek Mahar

답변:


268

불변은 객체의 생성자가 실행을 완료하면 해당 인스턴스를 변경할 수 없음을 의미합니다.

이는 다른 사람이 내용을 변경할 염려없이 객체에 대한 참조를 전달할 수 있다는 점에서 유용합니다. 특히 동시성을 처리 할 때 절대 바뀌지 않는 객체에 잠금 문제가 없습니다.

예 :

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.

Eric Lippert는 이에 대해 블로그 기사 를 작성했습니다. 기본적으로 인터페이스는 변경할 수 없지만 장면 뒤에 실제 변경 가능 개인 상태 (따라서 스레드간에 안전하게 공유 할 수 없음) 뒤에 객체를 가질 수 있습니다.


3
적어도 한 번은 값을 할당하기 위해 하나의 arg 생성자를 추가해야한다고 생각합니다. 실제로 변경할 값이 없으므로 현재 코드의 요점이 명확하지 않습니다. :).
Georgy Bolyuba

4
필드를 읽기 전용으로 만들어야합니다. 필드가 변경 불가능하다는 것을 완전히 명시합니다. 지금은 컨벤션으로 변경할 수 없습니다
JaredPar

7
myVar 멤버는 최종적으로 변경 불가능합니다.
laz

13
Foo 외부에서 myVar에 액세스 할 수없는 것이 맞습니다. 그러나 final의 존재는 미래에 클래스를 수정하는 사람에게 그 가치가 변하지 않는다는 것을 나타냅니다. 나는 그러한 상황에서 가능한 한 명백한 태도를 선호합니다.
laz

2
"최종 키워드를 사용해서 만 참조 유형을 변경할 수 없습니다. final은 재 할당 만 방지합니다." 에서 en.wikipedia.org/wiki/Immutable_object
Yousha Aleayoub

81

불변 개체는 내부 필드 (또는 외부 동작에 영향을 미치는 모든 내부 필드)를 변경할 수없는 개체입니다.

변경 불가능한 문자열에는 많은 장점이 있습니다.

성능 : 다음 작업을 수행하십시오.

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

substring () 메소드의 기본 C는 다음과 같습니다.

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

두 줄 모두 네 번째 문자를 문자 "a"로 바꿉니다. 두 번째 코드는 더 읽기 쉽고 빠를뿐입니다. foo에 대한 기본 코드를 어떻게 수행해야하는지 살펴보십시오. 부분 문자열은 쉽지만, 이제 5 번째 공간에 문자가 있고 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));

연결은 두 번 호출 되므로 전체 문자열을 반복해야합니다. bar작업을 위해 이것을 C 코드와 비교하십시오 .

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객체가 로컬 참조이며, 당신은 동시성의 안전에 대해 걱정할 필요가 없습니다 (하나의 스레드는 이제까지 그것을 접촉). 그리고 다른 곳에서는 참조되지 않기 때문에 스택에만 할당되므로 함수 호출이 완료되는 즉시 할당이 해제됩니다 (가비지 수집에 대해 걱정할 필요가 없습니다). 또한 가변성과 불변성의 성능 이점을 모두 얻을 수 있습니다.


4
잘 읽었습니다! if (! first)가 아니라 if (first)이어야한다고 생각하는 것 하나
Siddhartha

필드가 불변 인 것이 아니라 객체의 정의 된 관찰 가능 상태가 불변 인 것이 필요하다. 그 안에 포함 된 상태를 캡슐화하는 수단으로서 다른 객체에 대한 참조를 유지하는 객체 는 외부 세계에 노출되는 모든 캡슐화 된 상태가 마찬가지로 불변 인 경우에만 불변 일 수있다. 필드가 변경 불가능한 유형일 필요는 없습니다. 중요한 것은 보이는 상태입니다.
supercat

7
Passing pointers because Java is pass-by-reference자바 "값을 전달하지 않습니까?"
Cristian Gutu

@CristianGutu 예를 바로 JAVA는 "값에 의해 패스"없습니다 "참조 패스"입니다입니다
Arsh Kaushal

참조는 값으로 전달됩니다 !!
devv

31

위에서 제안한 Wikipedia 정의를 사용하면 실제로 String은 변경할 수 없습니다.

String의 상태는 시공 후 변경됩니다. hashcode () 메소드를 살펴보십시오. String은 해시 코드 값을 로컬 필드에 캐시하지만 hashcode ()를 처음 호출 할 때까지 값을 계산하지 않습니다. 해시 코드에 대한이 게으른 평가는 String을 상태가 변하는 불변의 객체로 흥미로운 위치에 배치하지만 리플렉션을 사용하지 않고는 변경 될 수 없습니다.

따라서 불변의 정의는 변경 될 수없는 개체 여야합니다.

불변 객체가 생성 된 후 상태가 변경되었지만 아무도 (반사없이) 그것을 볼 수 없다면 객체는 여전히 불변입니까?


1
좋은 아이디어-외부에서 물체를 바꿀 수있는 방법은없고 변화된 것으로 관찰 될 수없는 물체. hashCode ()의 private 필드는 객체의 외부에서 볼 수있는 상태에 중요하지 않은 내부 변경입니다.
mparaz

2
실제로 반사를 사용하면 변경된 것으로 관찰 될 있습니다. 리플렉션을 허용하면 Sedgewick의 Strings는 변경 가능합니다 .
Miguel

24

불변 개체는 프로그래밍 방식으로 변경할 수없는 개체입니다. 다중 스레드 환경 또는 둘 이상의 프로세스가 객체의 값을 변경 (돌연변이) 할 수있는 기타 환경에 특히 유용합니다.

그러나 명확히하기 위해 StringBuilder는 실제로 변경할 수없는 객체가 아닌 변경 가능한 객체입니다. 일반 Java 문자열은 변경할 수 없습니다. 일단 생성되면 객체를 변경하지 않고 기본 문자열을 변경할 수 없습니다.

예를 들어 String 값과 String 색상을 가진 ColoredString이라는 클래스가 있다고 가정 해 보겠습니다.

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은 새로운 ColoredString 클래스를 만들지 않고 주요 속성 중 하나를 변경 (변경) 할 수 있기 때문에 변경 가능하다고합니다. 이것이 좋지 않은 이유는 예를 들어 여러 스레드가있는 GUI 응용 프로그램이 있고 ColoredStrings를 사용하여 데이터를 창에 인쇄한다고 가정 해 봅시다. 다음과 같이 생성 된 ColoredString 인스턴스가있는 경우

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

그러면 문자열이 항상 "파란색"이됩니다. 그러나 다른 스레드가이 인스턴스를 잡고 호출 한 경우

blueString.setColor("Red");

갑자기 "파란색"문자열을 원할 때 갑자기 "빨간색"문자열이 나타납니다. 이 때문에 불변의 객체는 거의 항상 객체의 인스턴스를 전달할 때 선호됩니다. 변경 가능한 객체가 실제로 필요한 경우에는 일반적으로 특정 제어 필드에서 사본을 전달하여 오브 제트를 보호해야합니다.

요약하자면, Java에서 java.lang.String은 변경할 수없는 객체 (생성 된 후에 변경할 수 없음 )이고 java.lang.StringBuilder는 새로운 인스턴스를 만들지 않고 변경할 수 있기 때문에 변경할 수있는 객체입니다.


필드를 읽기 전용으로 만들어야합니다. 지금 당신의 수업은 관습에 의해 불변입니다. 미래 개발자들에게 불변성이 의도적이라는 징후는 없습니다. 필드를 읽기 전용으로 설정하면 향후 개발자에 대한 의도를 명확히하는 데 도움이됩니다.
JaredPar

@JaredPar-실제로 클래스는 불변이 아닙니다 ... 문제가 발생할 수있는 이유를 보여주는 변이 가능한 클래스의 예입니다.
Jason Coco

1
@JaredPar-아, 그건 괜찮아요 :) 좀 더 명확하게 다시 작성하려고했지만 Douglas 's는 이미 잘 작성되어 있고 좋아하는 것 같습니다. 따라서 다른 예를 들겠습니다. 그러나 누군가 내가 실제로 재미 있다고 생각한 속성을 최종적으로 만들기 위해 실제로 그것을 편집했습니다 :)
Jason Coco

24
  1. 큰 응용 프로그램에서는 문자열 리터럴이 큰 메모리 비트를 차지하는 것이 일반적입니다. 따라서 메모리를 효율적으로 처리하기 위해 JVM은 "문자열 상수 풀"이라는 영역을 할당합니다 ( 메모리에서 참조되지 않은 문자열조차도 char [], 길이에 대한 int 및 해시 코드에 대한 int를 전달합니다. 대조적으로, 최대 8 개의 즉시 바이트가 필요합니다 )
  2. complier가 String 리터럴을 발견하면 풀이 동일한 리터럴이 있는지 확인합니다. 그리고 하나가 발견되면 새로운 리터럴에 대한 참조는 기존 문자열로 보내지고 새로운 '문자열 리터럴 객체'가 만들어지지 않습니다 (기존 문자열은 단순히 추가 참조를 얻습니다).
  3. 따라서 : 문자열 가변성은 메모리를 절약합니다 ...
  4. 그러나 변수 중 하나가 값을 변경하면 실제로는 메모리의 값이 아니라 변경된 참조만이므로 (아래 참조하는 다른 변수에는 영향을 미치지 않습니다) ....

문자열 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가 없다면 "Old String"은 여전히 ​​메모리에 있지만 액세스 할 수는 없습니다 ...


16

"불변"은 값을 변경할 수 없음을 의미합니다. String 클래스의 인스턴스가 있으면 값을 수정하는 것처럼 보이는 모든 메서드가 실제로 다른 String을 만듭니다.

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

변경 사항을 유지하려면 다음과 같이해야합니다. foo = foo.sustring (3);

컬렉션으로 작업 할 때 변경 불가능한 변경 가능과 변경 불가능할 수 있습니다. 변경 가능한 객체를지도의 키로 사용하고 값을 변경하면 어떻게 될지 생각합니다 (팁 : 생각 equalshashCode).


13

java.time

약간 늦었지만 변경 불가능한 객체가 무엇인지 이해하기 위해 새로운 Java 8 Date and Time API ( 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


8

SCJP Sun Certified Programmer for Java 5 Study Guide 의 설명이 정말 마음에 듭니다 .

Java의 메모리 효율성을 높이기 위해 JVM은 "문자열 상수 풀"이라는 특수한 메모리 영역을 별도로 설정합니다. 컴파일러에서 문자열 리터럴을 발견하면 풀에서 동일한 문자열이 이미 있는지 확인합니다. 일치하는 것이 있으면 새 리터럴에 대한 참조가 기존 문자열로 보내지고 새 문자열 리터럴 객체가 만들어지지 않습니다.


동일한 불변 객체 로이 작업을 수행 할 수 있어야하지만 너무 많은 런타임이 필요하다고 생각합니다.
Zan Lynx

8

변경할 수없는 객체는 생성 된 후에 상태를 변경할 수 없습니다.

가능한 한 불변의 객체를 사용해야하는 세 가지 주요 이유가 있습니다. 이로 인해 코드에 도입 된 버그 수를 줄이는 데 도움이됩니다.

  • 다른 방법으로 객체의 상태를 변경할 수 없다는 것을 알면 프로그램 작동 방식을 추론하기가 훨씬 쉽습니다.
  • 불변 객체는 자동으로 스레드 안전 (안전하게 게시되었다고 가정)하기 때문에 핀 다운이 어려운 멀티 스레딩 버그의 원인이되지 않습니다.
  • 불변 개체는 항상 같은 해시 코드를 가지므로 HashMap (또는 이와 유사한)의 키로 사용될 수 있습니다. 해시 테이블에있는 요소의 해시 코드가 변경되면 테이블에서 해당 항목을 찾으려고 시도하면 잘못된 위치를 찾게되므로 테이블 항목이 효과적으로 손실됩니다. 이것이 String 객체가 불변 인 주된 이유이며, 종종 HashMap 키로 사용됩니다.

예를 들어 계산 된 해시를 캐싱하는 것과 같이 객체의 상태가 변경 불가능하다는 것을 알고 코드에서 만들 수있는 다른 최적화 방법도 있지만 최적화 된 것이므로 그다지 흥미롭지는 않습니다.


5

예를 들어, .Net 문자열의 경우 메모리의 문자열을 변경할 수 없음을 의미합니다. 변경한다고 생각하면 실제로 새 문자열을 작성하는 중입니다. 메모리에있는 문자열로 기존 변수 (어딘가에있는 실제 문자 모음에 대한 포인터 일뿐)를 새 문자열로 지정합니다.


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" : 객체 s1 "Hi"값으로 가 작성되었습니다.

s2=s1 : s2s1 객체를 참조 하여 객체 가 생성됩니다.

s1="Bye": 문자열 유형이 있고 문자열 유형이 변경 불가능한 유형 s1이기 때문에 이전 오브젝트의 값은 변경되지 않습니다 s1. 대신 컴파일러는 "Bye"값을 사용하여 새 문자열 오브젝트를 작성하고 s1이를 참조합니다. 여기서 s2값 을 인쇄 할 때 "Hi"값을 가진 s2이전 s1개체를 참조 했기 때문에 결과가 "Bye" 가 아니라 "Hi"가됩니다.


약간의 설명을 추가 할 수 있습니까?
minigeek

3

변경할 수 없음은 일단 객체가 생성되면 해당 멤버 중 하나가 변경되지 않음을 의미합니다. String내용을 변경할 수 없으므로 변경할 수 없습니다. 예를 들면 다음과 같습니다.

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

위의 코드에서 문자열 s1은 변경되지 않았으며을 s2사용하여 다른 객체 ( )가 생성되었습니다 s1.


3

불변이란 단순히 변경 불가능하거나 수정할 수 없음을 의미합니다. 문자열 객체가 생성되면 데이터 또는 상태를 변경할 수 없습니다

다음 예제를 고려하십시오.

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

다음 다이어그램을 고려하여 아이디어를 얻도록하겠습니다.

여기에 이미지 설명을 입력하십시오

이 다이어그램에서 "미래 세계"로 생성 된 새 개체를 볼 수 있습니다. 그러나 "미래"를 변경하지 마십시오. Because String is immutable. s, 여전히 "미래"를 참조하십시오. "미래 세계"에 전화해야한다면

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

Java에서 문자열 객체를 변경할 수없는 이유는 무엇입니까?

Java는 문자열 리터럴 개념을 사용하기 때문입니다. 5 개의 기준 변수가 있고 모두 하나의 객체 "미래"를 참조한다고 가정합니다. 하나의 기준 변수가 객체의 값을 변경하면 모든 기준 변수에 영향을 미칩니다. 이것이 자바에서 문자열 객체가 불변 인 이유입니다.


2

일단 등록되면 변경할 수 없습니다. 인스턴스가 해시 테이블 또는 이와 유사한 키로 사용될 수있는 클래스를 고려하십시오. Java 우수 사례를 확인하십시오.


0

불변 개체

객체는 생성 된 후 상태가 변경되지 않으면 불변으로 간주됩니다. 불변의 객체에 대한 최대 의존도는 간단하고 안정적인 코드를 만들기위한 올바른 전략으로 널리 받아 들여지고 있습니다.

불변 개체는 동시 응용 프로그램에서 특히 유용합니다. 상태를 변경할 수 없으므로 스레드 간섭으로 인해 손상되거나 일관성이없는 상태에서 관찰 될 수 없습니다.

프로그래머는 종종 객체를 업데이트하는 대신 새로운 객체를 생성하는 비용에 대해 걱정하기 때문에 불변 객체를 사용하는 것을 꺼려합니다. 객체 생성의 영향은 종종 과대 평가되며 불변 객체와 관련된 일부 효율성으로 상쇄 될 수 있습니다. 여기에는 가비지 수집으로 인한 오버 헤드 감소 및 변경 가능한 객체의 손상을 방지하는 데 필요한 코드 제거가 포함됩니다.

다음 하위 섹션은 인스턴스가 변경 가능한 클래스를 가져 와서 변경할 수없는 인스턴스가있는 클래스를 파생시킵니다. 그렇게함으로써 이러한 종류의 변환에 대한 일반적인 규칙을 제공하고 불변 개체의 장점을 보여줍니다.

출처


0

수락 된 답변이 모든 질문에 대답하지는 않습니다. 나는 11 년 6 개월 후에 답변을 강요 받았다.

누군가 불변의 의미를 명확히 할 수 있습니까?

불변의 객체 를 의미하기를 바랍니다 ( 불변의 참조 에 대해 생각할 수 있기 때문에 ).

객체는 변경할 수 없습니다 . 일단 생성되면 항상 동일한 값을 나타냅니다 (값을 변경하는 메서드가 없음).

String 불변인가?

Sting.java 소스 코드 를 조사하여 확인할 수있는 위의 정의를 존중하십시오 .

불변 개체의 장점 / 단점은 무엇입니까? 불변 유형은 다음과 같습니다.

  • 버그로부터 더 안전합니다.

  • 이해하기 쉽다.

  • 더 많은 변화를 준비합니다.

StringBuilder와 같은 가변 객체가 String보다 우선해야하는 이유는 무엇입니까?

질문 좁히기 왜 프로그래밍에 가변 StringBuilder가 필요한가? 이를 위해 일반적으로 다음과 같이 많은 수의 문자열을 연결합니다.

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

불변 문자열을 사용하면 많은 임시 복사본이 만들어집니다. 마지막 문자열을 만드는 과정에서 첫 번째 문자열 ( "0")이 실제로 n 번 복사되고 두 번째 숫자가 n-1 번 복사되므로 의 위에. n 개의 요소 만 연결하더라도 실제로는 모든 복사를 수행하는 데 실제로 O (n2) 시간이 걸립니다.

StringBuilder는이 복사를 최소화하도록 설계되었습니다. toString () 호출로 최종 문자열을 요청할 때 끝까지 복사를 피하기 위해 간단하지만 영리한 내부 데이터 구조를 사용합니다.

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

좋은 성능을 얻는 것이 가변 객체를 사용하는 이유 중 하나입니다. 또 하나는 편리한 공유입니다. 프로그램의 두 부분은 공통의 가변 데이터 구조를 공유함으로써보다 편리하게 통신 할 수 있습니다.

자세한 내용은 여기에서 찾을 수 있습니다 : https://web.mit.edu/6.005/www/fa15/classes/09-immutability/#useful_immutable_types


-1

불변 개체는 생성 한 후에 수정할 수없는 개체입니다. 일반적인 예는 문자열 리터럴입니다.

점점 더 대중화되고있는 AD 프로그래밍 언어는 "불변"키워드를 통한 "불변성"이라는 개념을 가지고있다. - 그것에 대해이 Dr.Dobb의 기사 확인 http://dobbscodetalk.com/index.php?option=com_myblog&show=Invariant-Strings.html&Itemid=29을 . 문제를 완벽하게 설명합니다.


D 2.020부터 키워드가 불변에서 불변으로 변경되었다고 생각합니다. 요점은 보이지 않지만 "불변은 지금 구현되었습니다."라고 말합니다. digitalmars.com/d/2.0/changelog.html#new2_020
he_the_great
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.