정수 불변 임


102

나는 이것이 아마도 매우 어리 석다는 것을 알고 있지만, 많은 곳에서 Java의 Integer 클래스가 불변이라고 주장하지만 다음 코드는 다음과 같습니다.

Integer a=3;
Integer b=3;
a+=b;
System.out.println(a);

(예상 된) 결과를주는 데 아무런 문제없이 실행됩니다. 6. 따라서 a의 값이 효과적으로 변경되었습니다. 그것은 Integer가 변경 가능하다는 것을 의미하지 않습니까? 2 차 질문 및 약간의 주제를 벗어난 : "불변 클래스에는 복사 생성자가 필요하지 않습니다." 이유를 설명 해줄 사람이 있습니까?


12
클래스는 불변이지만 오토 박싱으로 인해 펑키 한 일이 일어나고 있습니다 : stackoverflow.com/questions/3085332/…
wkl

감사합니다, 권투는 내가 구글에 필요한 키워드였습니다 :)
K.Steff

7
불변성을 최종 또는 상수 값과 혼동하고 있습니다.
Code Enthusiastic

답변:


95

불변성은 a결코 다른 값과 같을 수 없음을 의미하지 않습니다 . 예를 들어 String는 변경 불가능하지만 여전히이 작업을 수행 할 수 있습니다.

String str = "hello";
// str equals "hello"
str = str + "world";
// now str equals "helloworld"

str변경되지 않았습니다. 오히려 str이제 완전히 새로 인스턴스화 된 객체 Integer입니다. 따라서의 값은 a변경되지 않았지만 완전히 새로운 객체, 즉 new Integer(6).


14
"이것은 str이 이제 완전히 새로 인스턴스화 된 객체이기 때문입니다." 또는 오히려 str (바리 발레) 은 새 객체를 가리 킵니다 . 객체 자체는 변경할 수 없지만 변수가 최종적이지 않기 때문에 다른 객체를 가리킬 수 있습니다.
Sandman 2011

예, +=작업 의 결과로 인스턴스화 된 다른 개체를 가리 킵니다 .
Travis Webb 2011

11
엄밀히 말하면 새로운 대상이 될 필요는 없습니다 . 권투 사용 및 그 방법은 개체 의 캐시를 유지 합니다. 따라서 변수 에 대한 결과는 이전에 존재했던 객체 일 수 있습니다 (또는 동일한 객체 일 수도 있습니다 ...의 경우 ). Integer.valueOf(int)Integer+=Integera += 0
Stephen C

1
JavaDoc for String은 명시 적으로 불변이라고 말하지만 JavaDoc for Integer는 그렇지 않은 이유는 무엇입니까? 그 차이가 내가이 질문을 읽고있는 이유입니다 ...
cellepo

52

aInteger (3)에 대한 "참조"입니다. 속기는 a+=b실제로 다음을 수행하는 것을 의미합니다.

a = new Integer(3 + 3)

따라서 정수는 변경할 수 없지만이를 가리키는 변수는 *입니다.

* 불변 변수를 가질 수 있습니다. 이러한 변수는 키워드로 표시되며 final참조가 변경되지 않을 수 있습니다.

final Integer a = 3;
final Integer b = 3;
a += b; // compile error, the variable `a` is immutable, too.

20

다음을 사용하여 객체가 변경되었는지 확인할 수 있습니다 System.identityHashCode()(더 나은 방법은 일반을 사용하는 ==것이지만 값이 아닌 참조가 변경된 것은 분명하지 않음).

Integer a = 3;
System.out.println("before a +=3; a="+a+" id="+Integer.toHexString(System.identityHashCode(a)));
a += 3;
System.out.println("after a +=3; a="+a+" id="+Integer.toHexString(System.identityHashCode(a)));

인쇄물

before a +=3; a=3 id=70f9f9d8
after a +=3; a=6 id=2b820dda

개체의 기본 "id"를 볼 수 있습니다. a 가 변경되었음을 알 수 있습니다.


1
System.identityHashCode ()는 아주 좋은 팁입니다. 감사합니다.
Ad Infinitum

11

초기 질문에 대해

Integer a=3;
Integer b=3;
a+=b;
System.out.println(a);

정수는 불변이므로 위에서 발생한 것은 'a'가 값 6의 새로운 참조로 변경된 것입니다. 초기 값 3은 메모리에 참조가없는 상태로 남아 있으므로 (변경되지 않음) 가비지 수집 될 수 있습니다.

이것이 문자열에 발생하면 참조를 가질 것으로 예상되는 정수보다 더 오랜 기간 동안 풀 (PermGen 공간)에 보관됩니다.


8

예 Integer는 변경할 수 없습니다.

A는 객체를 가리키는 참조입니다. + = 3을 실행하면 A가 다른 값으로 새 Integer 개체를 참조하도록 다시 할당됩니다.

원래 개체를 수정 한 것이 아니라 다른 개체에 대한 참조를 가리 켰습니다.

여기 에서 객체와 참조의 차이점에 대해 읽어보십시오 .


다른 모든 복잡한 설명과 함께 평신도의 언어로 간단하고 쉽게 말할 수 있습니다. :)
Roshan Fernando

5

불변성은 변수의 값을 변경할 수 없음을 의미하지 않습니다. 새로운 할당은 새로운 객체를 생성하고 (새 메모리 위치에 할당) 값이 할당된다는 것을 의미합니다.

이것을 직접 이해하려면 루프에서 정수 할당을 수행하고 (루프 외부에서 정수 선언 됨) 메모리에있는 라이브 객체를 살펴보십시오.

불변 객체에 복사 생성자가 필요하지 않은 이유는 단순한 상식입니다. 각 할당은 새 객체를 생성하므로 언어는 기술적으로 이미 사본을 생성하므로 다른 사본을 생성 할 필요가 없습니다.


2

"불변 클래스에는 복사 생성자가 필요하지 않습니다." 이유를 설명 해줄 사람이 있습니까?

그 이유는 변경 불가능한 클래스의 인스턴스를 복사 할 필요 가 거의 없기 때문입니다 . 개체의 복사본은 원본과 "동일"해야하며 동일한 경우 만들 필요가 없습니다.

하지만 몇 가지 기본 가정이 있습니다.

  • 응용 프로그램이 클래스 인스턴스의 개체 ID에 어떤 의미도 부여하지 않는다고 가정합니다.

  • 이 메서드에 따라 클래스가 오버로드 equals되어 hashCode인스턴스의 복사본이 원본과 "동일" 하다고 가정합니다 .

이러한 가정 중 하나 또는 둘 모두 가 거짓 일 있으며 복사 생성자를 추가해야합니다.


1

이것이 내가 불변을 이해하는 방법입니다

int a=3;    
int b=a;
b=b+5;
System.out.println(a); //this returns 3
System.out.println(b); //this returns 8

int가 변경 될 수 있다면 "a"는 8을 인쇄하지만 변경 불가능하기 때문에 인쇄하지 않습니다. 그래서 3입니다. 귀하의 예제는 새로운 할당 일뿐입니다.


0

Integer (및 Float, Short 등과 같은 다른 신조)는 간단한 샘플 코드로 변경할 수 없음을 분명히 할 수 있습니다.

샘플 코드

public class Test{
    public static void main(String... args){
        Integer i = 100;
        StringBuilder sb = new StringBuilder("Hi");
        Test c = new Test();
        c.doInteger(i);
        c.doStringBuilder(sb);
        System.out.println(sb.append(i)); //Expected result if Integer is mutable is Hi there 1000
    }

    private void doInteger(Integer i){
        i=1000;
    }

    private void doStringBuilder(StringBuilder sb){
        sb.append(" there");
    }

}

실제 결과

결과는 예상 된 결과 대신 Hi There 100 (sb와 i가 모두 변경 가능한 객체 인 경우) Hi There 1000

이것은 main에서 i에 의해 생성 된 객체가 수정되지 않은 반면 sb는 수정되었음을 보여줍니다.

그래서 StringBuilder는 Integer가 아닌 가변 동작을 보여주었습니다.

따라서 Integer는 불변입니다. 따라서 입증

정수만없는 또 다른 코드 :

public class Test{
    public static void main(String... args){
        Integer i = 100;
        Test c = new Test();
        c.doInteger(i);
        System.out.println(i); //Expected result is 1000 in case Integer is mutable
    }

    private void doInteger(Integer i){
        i=1000;
    }


}

정수를 다시 할당하고 stringbuilder에서 메서드를 호출하는 두 가지 작업을 수행하고 있습니다. 당신이 경우에 private void doStringBuilder(StringBuilder sb){ sb = new StringBuilder(); }다음 sb변경되지 않습니다.
MT0

Integer를 변경 가능한 다른 객체와 병치하기 위해 StringBuilder (변경 가능)를 추가했습니다. 당신은 당신이 모두 StringBuilder에 관련 코드를 삭제 할 수 있습니다 원한다면 그냥 (100)보고 인쇄 출력
아슈 니 감은

이 불변성을 증명하지 않는다 - 당신이하고있는 모두가 다시 해싱입니다 예를 자바가 사용하는 것을 보여 패스에 의해 값 (및 개체에 대해 전달 된 값이 포인터 있음)를.
MT0

시도private void doInteger(Integer i){ System.out.println( i == 100 ); i=1000; System.out.println( i == 100 ); }
MT0

@ MT0 값으로 전달할 때 StringBuilder는 여전히 동일한 객체를 가리키고 있지만 Integer는 동일한 객체에 대한 참조가 아닌 새 사본을 전달합니다. doInteger로 출력하면 주 함수가 아닌 함수가 소유 한 사본을 표시합니다. main에서 i가 가리키는 객체가 같은지 확인하고 싶습니다. 개념이 명확 해지기를 바랍니다. :) 또한 StringBuilder의 불변 버전은 String입니다. 샘플을 공유하려면 알려주세요.
Ashutosh Nigam

-1
public static void main(String[] args) {
    // TODO Auto-generated method stub

    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

    Integer i=1000;
    Integer i2=i;

    i=5000;

    System.out.println(i2); // 1000
    System.out.println(i); // 5000

    int j=1000;
    int j2=j;

    j=5000;

    System.out.println(j2); // 1000
    System.out.println(j); //  5000


    char c='a';
    char b=c;

    c='d';

    System.out.println(c); // d
    System.out.println(b); // a
}

출력은 다음과 같습니다.

안녕 안녕 1000 5000 1000 5000 d a

따라서 char는 변경 가능하고 String Integer 및 int는 변경 불가능합니다.


1
이 답변은 다른 사람의 정보를 제공하지 않습니다.
Giulio Caccin
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.